Skip to main content
All docs
V19.1

How to: Edit a Reference Property in the Batch Edit Mode

  • 8 minutes to read

By default, the batch edit mode does not support the editing of reference property values. However, you can enable this option in your project for a specific reference property. In ASP.NET applications, ASPxGridView performs batch editing on the client side, it is not possible to process or pass values from editors placed inside templates on the server side. Thus, in this example, all processing is performed on the client side.

Tip

A complete sample project is available in the DevExpress Code Examples database at xref:113249#batch-edit-mode-specificities.

The following steps demonstrate how to create a custom editor inside the custom ReferencedTemplate template.

  1. Create the following ExampleObject and ReferencedObject business classes. Add the ExampleObject.LookupReferencedObject reference property of the ReferencedObject type.

    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.BaseImpl;
    using DevExpress.Xpo;
    // ...
    [DefaultClassOptions]
    public class ExampleObject : BaseObject {
        private string name;
        private ReferencedObject lookupReferencedObject;
        public ExampleObject(Session session) : base(session) {}
        public string Name {
            get { return name; }
            set { SetPropertyValue("Name", ref name, value); }
        }
        public ReferencedObject LookupReferencedObject {
            get { return lookupReferencedObject; }
            set { SetPropertyValue("LookupReferencedObject", ref lookupReferencedObject, value); }
        }
    }
    [DefaultClassOptions]
    public class ReferencedObject : XPObject {
        private string name;
        public ReferencedObject(Session session) : base(session) { }
        public string Name {
            get { return name; }
            set { SetPropertyValue("Name", ref name, value); }
        }
    }
    
  2. Add the ReferencedTemplate class to the Editors folder of the ASP.NET module project. Implement the ITemplate.InstantiateIn method to create a new ASPxComboBox editor containing ReferencedObject items and the “N/A” item.

    using System.Collections.Generic;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using DevExpress.Web;
    //...
    class ReferencedTemplate : ITemplate {
        //Handle the editor's client-side event to emulate the behavior of standard ASPxClientTextEdit.KeyDown grid editor. 
        const string BatchEditKeyDown =
            @"function(s, e) {
                var keyCode = ASPxClientUtils.GetKeyCode(e.htmlEvent);
                if (keyCode !== ASPx.Key.Tab && keyCode !== ASPx.Key.Enter) 
                    return;
                var moveActionName = e.htmlEvent.shiftKey ? 'MoveFocusBackward' : 'MoveFocusForward';
                var clientGridView = s.grid;
                if (clientGridView.batchEditApi[moveActionName]()) {
                    ASPxClientUtils.PreventEventAndBubble(e.htmlEvent);
                    window.batchPreventEndEditOnLostFocus = true;
                }
            }";
        //Handle the editor's client-side event to emulate the behavior of standard ASPxClientEdit.LostFocus grid editor. 
        const string BatchEditLostFocus =
            @"function (s, e) {
                var clientGridView = s.grid;
                if (!window.batchPreventEndEditOnLostFocus)
                    clientGridView.batchEditApi.EndEdit();
                window.batchPreventEndEditOnLostFocus = false;
            }";
        public IEnumerable<ReferencedObject> Objects { get; private set; }
        public ReferencedTemplate(IEnumerable<ReferencedObject> objects) {
            Objects = objects;
        }
        public void InstantiateIn(Control container) {
            GridViewEditItemTemplateContainer gridContainer = (GridViewEditItemTemplateContainer)container;
    
            ASPxComboBox comboBox = new ASPxComboBox();
            comboBox.Width = Unit.Percentage(100);
            comboBox.ClientInstanceName = "ReferencedEdit";
            comboBox.ClientSideEvents.KeyDown = BatchEditKeyDown;
    
            comboBox.ClientSideEvents.LostFocus = BatchEditLostFocus;
    
            ListEditItem notAssignedItem = new ListEditItem("N/A", null);
            comboBox.Items.Add(notAssignedItem);
    
            foreach (var currentObject in Objects) {
                ListEditItem item = new ListEditItem(currentObject.Name, currentObject.Oid);
                comboBox.Items.Add(item);
            }
            container.Controls.Add(comboBox);
        }
    }
    
  3. Finally, create the CreateCustomEditItemTemplateController in the Controllers folder of the ASP.NET module project to subscribe to client-side events and update cell values as demonstrates below.

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Web.Editors.ASPx;
    using DevExpress.ExpressApp.Web.Utils;
    using DevExpress.Web;
    using DevExpress.Xpo;
    using System.Collections.Generic;
    using System.Linq;
    //...
    public class CreateCustomEditItemTemplateController : ViewController<ListView> {
        //Handle the client-side event to set the grid's cell values to the editor.
        const string BatchEditStartEditing =
            @"function(s,e) {     
                var productNameColumn = s.GetColumnByField('LookupReferencedObject.Oid');
                if (!e.rowValues.hasOwnProperty(productNameColumn.index))
                    return;
                var cellInfo = e.rowValues[productNameColumn.index];
                ReferencedEdit.SetText(cellInfo.text);
                ReferencedEdit.SetValue(cellInfo.value);
                ReferencedEdit['grid'] = s;
                if (e.focusedColumn === productNameColumn) {
                    ReferencedEdit.SetFocus();
                }
            }";
        //Handle the event to pass the value from the editor to the grid cell.
        const string BatchEditEndEditing =
            @"function(s,e){ 
                var productNameColumn = s.GetColumnByField('LookupReferencedObject.Oid');
                if (!e.rowValues.hasOwnProperty(productNameColumn.index))
                    return;
                var cellInfo = e.rowValues[productNameColumn.index];
                cellInfo.value = ReferencedEdit.GetValue();
                cellInfo.text = ReferencedEdit.GetText();
                ReferencedEdit.SetValue(null);
            }";
        public CreateCustomEditItemTemplateController() {
            TargetObjectType = typeof(ExampleObject);
        }
        protected override void OnActivated() {
            base.OnActivated();
            ASPxGridListEditor listEditor = (ASPxGridListEditor)View.Editor;
            listEditor.CreateCustomEditItemTemplate += listEditor_CreateCustomEditItemTemplate;
            listEditor.CreateCustomGridViewDataColumn += listEditor_CreateCustomGridViewDataColumn;
        }
        protected override void OnDeactivated() {
            ASPxGridListEditor listEditor = (ASPxGridListEditor)View.Editor;
            listEditor.CreateCustomEditItemTemplate -= listEditor_CreateCustomEditItemTemplate;
            listEditor.CreateCustomGridViewDataColumn -= listEditor_CreateCustomGridViewDataColumn;
            base.OnDeactivated();
        }
        private void listEditor_CreateCustomGridViewDataColumn(object sender, CreateCustomGridViewDataColumnEventArgs e) {
            if (e.ModelColumn.PropertyEditorType == typeof(ASPxLookupPropertyEditor)) {
                if (e.ModelColumn.PropertyName == "LookupReferencedObject") {
                    var gridColumn = new GridViewDataComboBoxColumn();
                    gridColumn.Name = e.ModelColumn.PropertyName;
                    gridColumn.FieldName = e.ModelColumn.PropertyName + ".Oid";
                    gridColumn.PropertiesComboBox.ValueType = typeof(int?);
                    gridColumn.PropertiesComboBox.ValueField = "Oid";
                    gridColumn.PropertiesComboBox.TextField = "Name";
                    gridColumn.PropertiesComboBox.DataSource = ObjectSpace.GetObjects<ReferencedObject>();
                    e.Column = gridColumn;
                }
            }
        }
        private void listEditor_CreateCustomEditItemTemplate(object sender, CreateCustomEditItemTemplateEventArgs e) {
            if (e.ModelColumn.PropertyName == "LookupReferencedObject") {
                IEnumerable<ReferencedObject> referencedObjectsList = 
                    ObjectSpace.CreateCollection(typeof(ReferencedObject), null, 
                    new SortProperty[] { new SortProperty("Name", 
                    DevExpress.Xpo.DB.SortingDirection.Ascending) }).Cast<ReferencedObject>();
                e.Template = new ReferencedTemplate(referencedObjectsList);
                e.Handled = true;
            }
        }
        protected void BatchValueIsUpdated(object sender, CustomUpdateBatchValueEventArgs e) {
            if (e.PropertyName == "LookupReferencedObject.Oid") {
                var exampleObject = e.Object as ExampleObject;
                if (e.NewValue == null) {
                    exampleObject.LookupReferencedObject = null;
                } else {
                    exampleObject.LookupReferencedObject = exampleObject.Session.GetObjectByKey<ReferencedObject>(e.NewValue);
                }
                e.Handled = true;
            }
        }
        protected override void OnViewControlsCreated() {
            base.OnViewControlsCreated();
    
            ASPxGridListEditor gridListEditor = View.Editor as ASPxGridListEditor;
            gridListEditor.BatchEditModeHelper.CustomUpdateBatchValue += BatchValueIsUpdated;
    
            string Grid_BatchEditStartEditingKey = "BatchEditStartEditingKey";
            ClientSideEventsHelper.AssignClientHandlerSafe(gridListEditor.Grid, "BatchEditStartEditing",
            BatchEditStartEditing, Grid_BatchEditStartEditingKey);
    
            string Grid_BatchEditEndEditingKey = "BatchEditEndEditingKey";
            ClientSideEventsHelper.AssignClientHandlerSafe(gridListEditor.Grid, "BatchEditEndEditing",
            BatchEditEndEditing, Grid_BatchEditEndEditingKey);
        }
    }
    

You can now run the application and see the result. The LookupReferencedObject values can now be edited in the batch mode.

ReferencedObjectExample