Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
585
UltraWinGrid sorted by column with ValueList and custom editor occasionally sorts by value
posted

I have a grid column with a custom editor that inherits from `EditorWithCombo`, like so:

    public class IDAndLabelEditorWithCombo<TDataObject> : EditorWithCombo
        where TDataObject : class
    {
        private readonly NLog.Logger Log =
            NLog.LogManager.GetCurrentClassLogger();

        public UltraGridColumn Column { get; private set; }
        public Func<int, bool, TDataObject, string> GetDisplayTextFunc { get; private set; }

        // we don't actually override this; this is just to test that the value is in fact 'false'
        public override bool ComparesByValue(EmbeddableEditorOwnerBase owner, object ownerContext)
        {
            var result = base.ComparesByValue(owner, ownerContext);
            Log.Debug(result);
            return result;
        }

        public IDAndLabelEditorWithCombo(UltraGridColumn column)
        {
            Column = column;
            GetDisplayTextFunc = null;
        }

        public IDAndLabelEditorWithCombo(UltraGridColumn column,
                                         Func<int, bool, TDataObject, string> customDisplayTextFunc)
        {
            Column = column;
            GetDisplayTextFunc = customDisplayTextFunc;
        }

        public override IValueList ValueList
        {
            get
            {
                if (!IsInEditMode)
                    return Column.ValueList;
                else
                    return base.ValueList;
            }
        }

        protected override string GetElementText(EmbeddableUIElementBase element, bool ignorePasswordChar)
        {
            if (element.GetContext(typeof(UltraGridCell)) is UltraGridCell cell)
                return DataValueToText(cell.Value, element.Owner, cell.Row);

            return base.GetElementText(element, ignorePasswordChar);
        }

        public override string DataValueToText(object valueToConvert, EmbeddableEditorOwnerBase owner, object ownerContext)
        {
            var showIDs = AdminOverrides.ShowIDs; // just internal code that returns a bool

            if (ownerContext is UltraGridRow)
            {
                if (valueToConvert == null ||
                    valueToConvert == DBNull.Value)
                {
                    return _DataValueToText(0, showIDs);
                }

                if (valueToConvert is int)
                {
                    int intVal = (int)valueToConvert;

                    if (intVal <= 0)
                        return _DataValueToText(0, showIDs);

                    var valueList = owner.GetValueList(ownerContext) as ValueList;

                    if (valueList == null)
                    {
                        Log.Debug($"{nameof(valueList)} is null ({nameof(valueToConvert)}: {valueToConvert}, {nameof(owner)}: {owner})");

                        return _DataValueToText(intVal, showIDs);
                    }

                    var item = valueList.FindByDataValue(intVal);

                    if (item != null)
                        return _DataValueToText(item, showIDs);

                    Log.Debug($"{nameof(item)} is null ({nameof(valueToConvert)}: {valueToConvert}, {nameof(owner)}: {owner})");

                    return _DataValueToText(intVal, showIDs);
                }
            }

            Log.Debug($"{nameof(ownerContext)} is not {nameof(UltraGridRow)}: {ownerContext} ({nameof(valueToConvert)}: {valueToConvert}, {nameof(owner)}: {owner})");

            return base.DataValueToText(valueToConvert, owner, ownerContext);
        }

        private string _DataValueToText(int v, bool showIDs)
        {
            if (v == 0)
                return showIDs ? "[0]" : "";

            return $"[{v}]";
        }

        private string _DataValueToText(ValueListItem item, bool showIDs)
        {
            var dataValue = (int)item.DataValue;
            var dataObject = item.Tag as TDataObject;
            var func = GetDisplayTextFunc;

            if (dataObject != null && func != null)
                return func(dataValue, showIDs, dataObject);

            return item.DisplayText +
                   (showIDs ? $"[{dataValue}]" : "");
        }
    }

The grid has `DataSource` set to a DataView, and that table contains values that are numeric IDs; this custom editor makes it so the user-displayed text is instead shown as a string. Admins can enable `AdminOverrides.ShowIDs` to also see the IDs, if they like. Nothing too special.

Sorting by this column should sort by the displayed text. For example, given a table:

ID Caption
1 Sarah
2 Andy
3 Daniel
4 Greg

Andy should show first, not Sarah. Indeed, this mostly happens.

But sometimes, such as when deleting a row from the underlying DataTable, the grid forgets this sort and instead sorts by ID. Even if I explicitly call `RefreshSort` (`DisplayLayout.Bands[0].SortedColumns.RefreshSort(false)`), the grid insists that the column is correctly sorted by Value, not by Text. Unless, that is, the user explicitly clicks the column again to reverse the sort, and then clicks it another time; now, the sort is by Text again.

I've checked that:

  • as this happens, the column is indeed still set to the custom editor class
  • `ComparesByValue` does return false even while this problem is happening (cf. the logging in the code above)
  • the column is also indeed in SortedColumns (and is the only column in there)

If I instead add or edit rows (rather than deleting one), the behavior doesn't seem to happen (or at least not as reproducibly).

This is with 21.1.20211.62 on .NET Framework 4.7.2. I haven't yet checked if this is fixed in a newer release.

Parents Reply Children
No Data