This project has moved and is read-only. For the latest updates, please go here.

PropertyGrid implementing ITypeEditor for flag enum using CheckComboBox

Feb 3, 2013 at 7:46 PM
Edited Feb 3, 2013 at 7:51 PM
Hello,
I am try'n to create my own ITypeEditor for enum flags. The code I use is mostly taken from the examples and discussion here. Please note, The code I 'm going to post now is an example I create just for posting here, no MVVM, no property change events, just plain code behind to keep it as simple as possible. As far as I can tell, the code is working except for one detail. If the enum is of multi value, like (em.AA | em.BB) only the first value is ever displayed in the CheckComboBox, and only the first value is selected in the dropdown.

If I selected multiple values in the dropdown, like CC and DD , the values is correctly displayed CC,DD and correctly parsed to the underlying object, in this case 12.

The binding in ResolveEditor actually resolves to "AA,BB" as it is supposed to, it just only displays and selects AA (always the first in the list only).

What AM I doing wrong, anyone any ideas, pointers?

Thanks

As for the code

the editor usercontrol xaml not much here,

<Grid>
    <extTK:CheckComboBox x:Name="cb" Grid.Row="0" Delimiter=","   SelectedValue="{Binding Value}" >

    </extTK:CheckComboBox>

</Grid>

the Editor usercontrol codebehind

public partial class FlagEnumTypeEditor : UserControl, ITypeEditor
{
    public FlagEnumTypeEditor()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(FlagEnumTypeEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    FrameworkElement ITypeEditor.ResolveEditor(PropertyItem pItem)
    {
        //Set available enum values.
        cb.ItemsSource = GetValues(pItem.PropertyType);

        var tt = pItem.Value.ToString();
        var mm = ((EmTestUsage)pItem.Value).ToString();
        Binding binding = new Binding("Value");
        binding.Converter = new EnumConverter(typeof(EmTestUsage));
        binding.Source = pItem;//.ToString();

        binding.Mode = BindingMode.TwoWay;// pItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay;
        BindingOperations.SetBinding(this, FlagEnumTypeEditor.ValueProperty, binding);

        return this;
    }


    private static object[] GetValues(Type enumType)
    {
        #region MyRegion
        List<object> values = new List<object>();

        var fields = enumType.GetFields().Where(x => x.IsLiteral);
        foreach (FieldInfo field in fields)
        {
            if (field.Name.Equals("None")||field.Name.Equals("All"))
                continue;//

            object[] attrs = field.GetCustomAttributes(typeof(BrowsableAttribute), false);
            if (attrs.Length == 1)
            {
                // If attribute exists and its value is false continue to the next field...
                BrowsableAttribute brAttr = (BrowsableAttribute)attrs[0];
                if (brAttr.Browsable == false)
                    continue;
            }

            values.Add(field.GetValue(enumType).ToString());
        }

        return values.ToArray(); 
        #endregion
    }
    private sealed class EnumConverter : IValueConverter
    {
        #region MyRegion
        private readonly Type m_enumType;

        internal EnumConverter(Type enumType)
        {
            m_enumType = enumType;
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return string.Empty;
            var t = value.ToString().Replace(" ", string.Empty);
            return t;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var newValue = Enum.Parse(m_enumType, value.ToString());
            return newValue;
        } 
        #endregion
    }
}

Enum and DTO class

[Flags]
public enum EmTestUsage
{
    None = 0,
    AA = 1,
    BB = 2,
    CC = 4,
    DD = 8,
    All = AA | BB | CC | DD
}

  public class TestDTO
  {
    [Browsable(false)]
    public Guid ComponentDetailsUUID { get; set; }

    [Category("I. General")]
    [DisplayName("1. ID / Key")]
    public string CompID { get; set; }

    [Category("II. Enum")]
    [DisplayName("1. Flag Enum Integer")]
    //[Editor(typeof(FlagEnumTypeEditor), typeof(FlagEnumTypeEditor))]
    public int EnumUsageKey { get; set; }

    [Category("II. Enum")]
    [DisplayName("2. Flag Enum Editor")]
    [Editor(typeof(FlagEnumTypeEditor), typeof(FlagEnumTypeEditor))]
    public EmTestUsage EnumUsage2 { get; set; }
}

the xaml

<extTK:PropertyGrid x:Name="pGrid" Grid.Row="0" Grid.Column="0" 
                         AutoGenerateProperties="True"
                        SelectedObject="{Binding TestDataSource}" />
    <Button Grid.Row="0" Grid.Column="1" Content="Load Object" Click="Button_Click" />

    <StackPanel Grid.Row="1" Orientation="Vertical">
        <TextBlock x:Name="txtOut1" />
        <TextBlock x:Name="txtOut2" />
        <Button Content="View selected value" Click="Button_Click_1" Height="30" />
    </StackPanel>
the two button click events,

just to bind the object, and display selected enums for testing

  private void Button_Click(object sender, RoutedEventArgs e)
    {
        pGrid.SelectedObject = new TestDTO()
        {
            ComponentDetailsUUID = Guid.NewGuid(),
            CompID = "A1234",
            EnumUsageKey = (int)(EmTestUsage.AA | EmTestUsage.BB),
            EnumUsage2 = (EmTestUsage.AA | EmTestUsage.BB)
        };
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    { //this will display the correct values as selected in the editor
        txtOut1.Text = ((TestDTO)pGrid.SelectedObject).EnumUsage2.ToString();
        txtOut2.Text = ((int)((TestDTO)pGrid.SelectedObject).EnumUsage2).ToString();
    }
Feb 5, 2013 at 3:04 AM
nvm, I found a simpler way using the simple class implementation, this usercontrol, was way to complex for the task,
Any OP, fee free to delete this thread