Search code examples
c#wpfpropertygridxceed

Xceed Property Grid Can't Completely See or Click Select Null values


I'm using the Xceed PropertyGrid with data binding and AutoGenerateProperties = true. I have nullable properties like described below that result in a strange UI behavior.

The grid lets me click on the values Yes and No but the null choice is slightly obsecured by the property grid and won't allow me to click on it to select it. If I select Yes and use the UP Arrow key I'm able to select it. The Microsoft property grid full shows the empty choice and allows me to click it.

Am I doing something wrong or is this a bug? I asked in GitHub Issues but have had no responses to my issue.

YesNo? _compressed;
[CategoryAttribute("Package")]
[Description("Set to 'yes' to have compressed files in the source. This attribute cannot be set for merge modules. ")]
public YesNo? Compressed { get { return _compressed; } set { _compressed = value; RaisePropertyChangedEvent("Compressed"); } }

enter image description here


Solution

  • This is not a bug really. If you want to display the value of default(YesNo?) as something else than an empty string or null, you need to define how you want it to be displayed somehow. You could do this by creating your own custom editor:

    public class CustomEditor<T> : Xceed.Wpf.Toolkit.PropertyGrid.Editors.ComboBoxEditor
    {
        protected override IValueConverter CreateValueConverter()
        {
            return new CustomValueConverter<T>();
        }
    
        protected override ComboBox CreateEditor()
        {
            ComboBox comboBox = base.CreateEditor();
            FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock));
            textBlock.SetBinding(TextBlock.TextProperty, new Binding(".") { Converter = new CustomValueConverter<T>() });
            comboBox.ItemTemplate = new DataTemplate() { VisualTree = textBlock };
            return comboBox;
        }
    
        protected override IEnumerable CreateItemsSource(Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyItem)
        {
            return new string[1] { CustomValueConverter<T>.Null }
                .Concat(Enum.GetValues(typeof(T)).OfType<T>().Select(x => x.ToString()));
        }
    }
    
    public class CustomValueConverter<T>: IValueConverter
    {
        internal const string Null = "";
        public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return Null;
    
            return value.ToString();
        }
    
        public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
        {
            string s = value?.ToString();
            if (s == Null)
                return null;
    
            return Enum.Parse(typeof(T), s);
        }
    }
    

    Usage:

    YesNo? _compressed;
    [CategoryAttribute("Package")]
    [Description("Set to 'yes' to have compressed files in the source. This attribute cannot be set for merge modules. ")]
    [Editor(typeof(CustomEditor<YesNo>), typeof(CustomEditor<YesNo>))]
    public YesNo? Compressed { get { return _compressed; } set { _compressed = value; RaisePropertyChangedEvent("Compressed"); } }