Current filter:
                                You should refresh the page.
                                  • I have built a custom propertyeditor based on concept from E689 which utilises KeyValuePair as it's datasource. The code is pasted below:

                                    [C#]
                                    using System; using System.Data; using System.Web.UI.WebControls; using DevExpress.ExpressApp.Model; using DevExpress.ExpressApp.Utils; using DevExpress.Web; using DevExpress.ExpressApp.Editors; using DevExpress.ExpressApp.Web.Editors.ASPx; using System.Collections; using DevExpress.ExpressApp.Xpo; using DevExpress.ExpressApp; using DevExpress.Persistent.BaseImpl; using System.Collections.Generic; using System.Linq; namespace E689.Module.Web.Editors { [PropertyEditor(typeof(string),"MultiSelectionPropertyEditor", false)] public class ASPxMultiSelectionPropertyEditor_1 : ASPxPropertyEditor, IComplexViewItem { private const string LookupIdColumnName = "Oid"; private const string LookupValueColumnName = "Value"; public ASPxMultiSelectionPropertyEditor_1(Type objectType, IModelMemberViewItem model) : base(objectType, model) { } protected override System.Web.UI.WebControls.WebControl CreateEditModeControlCore() { ASPxGridLookup lookupEdit = new ASPxGridLookup(); lookupEdit.ID = PropertyName + "_CheckedComboBox"; lookupEdit.Width = Unit.Percentage(100); lookupEdit.SelectionMode = GridLookupSelectionMode.Multiple; lookupEdit.TextChanged += EditValueChangedHandler; lookupEdit.KeyFieldName = LookupIdColumnName; lookupEdit.MultiTextSeparator = ", "; lookupEdit.AllowUserInput = false; lookupEdit.TextFormatString = "{1}"; string setSizeScript = "function(s, e){s.GetGridView().SetWidth(s.GetWidth()); }"; lookupEdit.ClientSideEvents.Init = lookupEdit.ClientSideEvents.DropDown = setSizeScript; lookupEdit.GridViewProperties.Settings.ShowColumnHeaders = true; lookupEdit.GridViewProperties.Settings.GridLines = GridLines.None; lookupEdit.GridViewStyles.SelectedRow.BackColor = System.Drawing.ColorTranslator.FromHtml("#00fbfbfb"); lookupEdit.GridViewStyles.FocusedRow.BackColor = System.Drawing.ColorTranslator.FromHtml("#00fbfbfb"); lookupEdit.IncrementalFilteringMode = IncrementalFilteringMode.Contains; GridViewCommandColumn selectionColumn = new GridViewCommandColumn(); selectionColumn.ShowSelectCheckbox = true; lookupEdit.Columns.Add(selectionColumn); GridViewDataColumn idColumn = new GridViewDataColumn(LookupIdColumnName); idColumn.Visible = false; lookupEdit.Columns.Add(idColumn); GridViewDataColumn valueColumn = new GridViewDataColumn(LookupValueColumnName); lookupEdit.Columns.Add(valueColumn); lookupEdit.DataSource = GetLookupData(); return lookupEdit; } private DataTable GetLookupData() { DataTable table = new DataTable(); table.Columns.Add(LookupIdColumnName, typeof(int)); table.Columns.Add(LookupValueColumnName, typeof(string)); foreach (KeyValuePair<int,string> item in DemoObject3.Options) { if (!IsNoneValue(item.Value)) { table.Rows.Add(item.Key, item.Value); } } return table; } public override void BreakLinksToControl(bool unwireEventsOnly) { ASPxGridLookup lookupEdit = Editor as ASPxGridLookup; if(lookupEdit != null) { lookupEdit.TextChanged -= EditValueChangedHandler; } base.BreakLinksToControl(unwireEventsOnly); } protected override void ReadViewModeValueCore() { base.ReadViewModeValueCore(); Label viewModeControl = InplaceViewModeEditor as Label; if(viewModeControl != null) { viewModeControl.Text = ConvertToLocalizedString(viewModeControl.Text); } } protected override void ReadEditModeValueCore() { if(Editor != null) { Editor.Text = PropertyValue == null ? String.Empty : ConvertToLocalizedString(PropertyValue.ToString()); } } protected override object GetControlValueCore() { if(Editor != null) { if(String.IsNullOrEmpty(Editor.Text)) { return GetNoneValue(); } else { //return string.Join(Editor.MultiTextSeparator, Editor.GridView.GetSelectedFieldValues(LookupIdColumnName)); return Editor.Text; } } else { return base.GetControlValueCore(); } } private string ConvertToLocalizedString(ICollectionWrapper wrapper) { return wrapper.GetSelectedItemKeys(); } private string ConvertToLocalizedString(string unlocalizedString) { string result = unlocalizedString; foreach (KeyValuePair<int,string> item in DemoObject3.Options) { string localizedValue = item.Value; result = result.Replace(item.ToString(), localizedValue); } return result; } private string ConvertFromLocalizedString(string localizedString) { string result = localizedString; foreach (KeyValuePair<int, string> item in DemoObject3.Options) { string localizedValue = item.Value; result = result.Replace(localizedValue, item.ToString()); } return result; } protected override void SetImmediatePostDataScript(string script) { Editor.ClientSideEvents.CloseUp = script; } public new ASPxGridLookup Editor { get { return (ASPxGridLookup)base.Editor; } } private bool IsNoneValue(object value) { if(value is string) return false; int result = int.MinValue; try { result = Convert.ToInt32(value); } catch { } return 0.Equals(result); } private object GetNoneValue() { return DemoObject3.Options.Where(o => o.Key == 0); } #region IComplexViewItem members private IObjectSpace objectSpace; private XafApplication application; void IComplexViewItem.Setup(IObjectSpace objectSpace, XafApplication application) { this.objectSpace = objectSpace; this.application = application; } public IObjectSpace ObjectSpace { get { return objectSpace; } } public XafApplication Application { get { return application; } } #endregion } }

                                    And following is the target object

                                    [C#]
                                    [DefaultClassOptions] public class DemoObject3 : BaseObject { public DemoObject3(Session session) : base(session) { } public static List<KeyValuePair<int, string>> Options = new List<KeyValuePair<int,string>>() { new KeyValuePair<int, string>(0, "N/A"), new KeyValuePair<int, string>(1, "Option1"), new KeyValuePair<int, string>(2, "Option2"), new KeyValuePair<int, string>(3, "Option3"), new KeyValuePair<int, string>(4, "Option4") }; private string someOption; //[ImmediatePostData] [EditorAlias("MultiSelectionPropertyEditor")] public string SomeOption { get { return someOption; } set { SetPropertyValue("SomeOption", ref someOption, value); } } }

                                    This works very well. But,

                                    1) I need to show selected item's text as comma separated list in the UI. But the underlying property should contain selected Ids rather than labels.  

                                    2) The underlying property is supposed to an IList object rather than string as of now. Which means the control is supposed to return an IList instead of string.

                                    3) I need to have immediatepostdata activated on the target property but it results in javascript error.

                                    Request urgent help in this matter.

                                    Thanks,
                                    Kinjal
                                Show all comments
                                • Kinjal Sonpal 04.21.2015

                                  It's been close to 24 hours for this urgent ticket. I need to solve this issue.

                                  Kinjal

                                • Michael (DevExpress Support) 04.21.2015
                                  Hello Kinjal.

                                  Please accept my apologies for the delayed response. I have modified your custom editor according to your requirements. Please try it and let me know your results.
                                  [C#]
                                  [PropertyEditor(typeof(IList<int>), "MultiSelectionPropertyEditor", false)] public class ASPxMultiSelectionPropertyEditor_1 : ASPxPropertyEditor { private const string LookupIdColumnName = "Oid"; private const string LookupValueColumnName = "Value"; public ASPxMultiSelectionPropertyEditor_1(Type objectType, IModelMemberViewItem model) : base(objectType, model) { } protected override System.Web.UI.WebControls.WebControl CreateEditModeControlCore() { ASPxGridLookup lookupEdit = new ASPxGridLookup(); lookupEdit.ID = PropertyName + "_CheckedComboBox"; lookupEdit.Width = Unit.Percentage(100); lookupEdit.SelectionMode = GridLookupSelectionMode.Multiple; lookupEdit.KeyFieldName = LookupIdColumnName; lookupEdit.MultiTextSeparator = ", "; lookupEdit.AllowUserInput = false; lookupEdit.TextFormatString = "{1}"; lookupEdit.GridView.SelectionChanged += EditValueChangedHandler; string setSizeScript = "function(s, e){s.GetGridView().SetWidth(s.GetWidth()); }"; lookupEdit.ClientSideEvents.Init = lookupEdit.ClientSideEvents.DropDown = setSizeScript; lookupEdit.GridViewProperties.Settings.ShowColumnHeaders = true; lookupEdit.GridViewProperties.Settings.GridLines = GridLines.None; lookupEdit.GridViewStyles.SelectedRow.BackColor = System.Drawing.ColorTranslator.FromHtml("#00fbfbfb"); lookupEdit.GridViewStyles.FocusedRow.BackColor = System.Drawing.ColorTranslator.FromHtml("#00fbfbfb"); lookupEdit.IncrementalFilteringMode = IncrementalFilteringMode.Contains; GridViewCommandColumn selectionColumn = new GridViewCommandColumn(); selectionColumn.ShowSelectCheckbox = true; lookupEdit.Columns.Add(selectionColumn); GridViewDataColumn idColumn = new GridViewDataColumn(LookupIdColumnName); idColumn.Visible = false; lookupEdit.Columns.Add(idColumn); GridViewDataColumn valueColumn = new GridViewDataColumn(LookupValueColumnName); lookupEdit.Columns.Add(valueColumn); lookupEdit.DataSource = GetLookupData(); return lookupEdit; } private DataTable GetLookupData() { DataTable table = new DataTable(); table.Columns.Add(LookupIdColumnName, typeof(int)); table.Columns.Add(LookupValueColumnName, typeof(string)); foreach (KeyValuePair<int, string> item in DemoObject3.Options) { if (item.Key != 0) { table.Rows.Add(item.Key, item.Value); } } return table; } public override void BreakLinksToControl(bool unwireEventsOnly) { ASPxGridLookup lookupEdit = Editor as ASPxGridLookup; if (lookupEdit != null) { lookupEdit.GridView.SelectionChanged -= EditValueChangedHandler; } base.BreakLinksToControl(unwireEventsOnly); } protected override void ReadViewModeValueCore() { Label viewModeControl = InplaceViewModeEditor as Label; if (viewModeControl != null) { StringBuilder sb = new StringBuilder(); IList<int> value = (IList<int>)PropertyValue; foreach (var v in value) { if (sb.Length > 0) sb.Append(", "); sb.Append(DemoObject3.Options.FirstOrDefault(x => x.Key == v).Value); } viewModeControl.Text = sb.ToString(); } } protected override void ReadEditModeValueCore() { if (Editor != null) { var selection = Editor.GridView.Selection; selection.BeginSelection(); selection.UnselectAll(); IList<int> value = (IList<int>)PropertyValue; foreach (var v in value) { selection.SelectRowByKey(v); } selection.EndSelection(); } } protected override void WriteValueCore() { if (Editor != null) { IList<int> value = (IList<int>)PropertyValue; value.Clear(); foreach (var v in Editor.GridView.GetSelectedFieldValues(LookupIdColumnName)) { value.Add((int)v); } } } protected override bool IsMemberSetterRequired() { return false; } protected override void SetImmediatePostDataScript(string script) { Editor.ClientSideEvents.CloseUp = script; } public new ASPxGridLookup Editor { get { return (ASPxGridLookup)base.Editor; } } }
                                  [C#]
                                  [DefaultClassOptions] public class DemoObject3 : BaseObject { public DemoObject3(Session session) : base(session) { } public static List<KeyValuePair<int, string>> Options = new List<KeyValuePair<int, string>>() { new KeyValuePair<int, string>(0, "N/A"), new KeyValuePair<int, string>(1, "Option1"), new KeyValuePair<int, string>(2, "Option2"), new KeyValuePair<int, string>(3, "Option3"), new KeyValuePair<int, string>(4, "Option4") }; private List<int> _SomeOption = new List<int>(); [EditorAlias("MultiSelectionPropertyEditor")] public List<int> SomeOption { get { return _SomeOption; } } }

                                  Note that since the property type now is List<int>, it is non-persistent. Refer to the Data Types Supported by XPO article.

                                • Kinjal Sonpal 04.21.2015

                                  Michael, Thanks for the corrections.

                                  The code works perfectly, but I need to show this item for inplace editing as well. Please advise.

                                  Also, ImmediatePostData still throws exception as attached in the screenshot.

                                  Thanks,
                                  Kinjal

                                • Kinjal Sonpal 04.22.2015

                                  Value of code when the exception is thrown is attached, if it helps.

                                • Michael (DevExpress Support) 04.22.2015
                                  I cannot reproduce this issue. The code I provide works corectly on my side in in-place edit mode and with the ImmediatePostData option. See the attached sample and video.
                                  Note that ImmediatePostData option is supported in detail views only.

                                • Kinjal Sonpal 04.23.2015

                                  Michael, the problem is solved after I upgraded to 14.2.7 from 14.2.4 version!

                                  Thanks for the resolution and support.
                                  Kinjal

                                • Kinjal Sonpal 04.23.2015

                                  But, now there's another problem. Pressing enter or tab does not trigger immediatepostdata in detailview when AllowUserInput is set to true. An explicit mouse click is required to trigger this. Please advise.

                                  Kinjal

                                • Michael (DevExpress Support) 04.24.2015
                                  I'm glad to hear that the error is gone after the update. To make ImmediatePostData work in both AllowUserInput modes, modify the editor code as follows:
                                  [C#]
                                  protected override void SetImmediatePostDataScript(string script) { Editor.ClientSideEvents.ValueChanged = script; }

                                1 Solution

                                Creation Date Importance Sort by
                                I've finally implemented this functionality with the help of DevExpress support and I'm posting this so that it helps others as well the ticket is closed with a solution. I guess the solution is pretty generic, though I suspect it may not be fully optimized for performance

                                The attached project is self explanatory with a set of BOs for testing.
                                • Michael (DevExpress Support) 05.20.2015

                                  I'm happy to hear that you've completed your task. Thank you for sharing your solution with others.