This project has moved. For the latest updates, please go here.

CheckComboBox and [Flags] enum

Mar 15, 2016 at 8:30 PM
I'm using Xceed Extended WPF Toolkit to display a enum with [Flags] attribute in a PropertyGrid

[Flags]
public enum TestEnum
{
Test1 = 1,
Test2 = 2,
Test3 = 4,
Test4 = 8,
Test5 = 16,
Test6 = 32,
Test7 = 64,
}

Because I can't know the enum definition at compile time, I would dynamically create an Enum using EnumBuilder. ( I can't rely on a compile-time enum. I would dynamically create an Enum using [EnumBuilder])

I created an editor to display the enum as CheckComboBox:

public class CheckComboBoxEditor : TypeEditor<CheckComboBox>, ITypeEditor
{
protected override void SetValueDependencyProperty()
{
    ValueProperty = CheckComboBox.SelectedValueProperty;
}

protected override CheckComboBox CreateEditor()
{
    return new CheckComboBox();
}

protected override void ResolveValueBinding(PropertyItem propertyItem)
{
    var _binding = new Binding("Value");
    _binding.Source = propertyItem;
    _binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    _binding.Mode = BindingMode.TwoWay;
    _binding.Converter = CreateValueConverter();
    BindingOperations.SetBinding(Editor, CheckComboBox.SelectedValueProperty, _binding);

    var _binding2 = new Binding("Value");
    _binding2.Source = propertyItem;
    _binding2.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    _binding2.Mode = BindingMode.TwoWay;
    _binding2.Converter = CreateValueConverter();
    BindingOperations.SetBinding(Editor, CheckComboBox.SelectedItemProperty, _binding2);

    Editor.ItemsSource = Enum.GetValues(propertyItem.Value.GetType());
}
}

As you can see, so far I've tried to bind each the SelectedValue and the SelectedItem property. CreateValueConverter() is defined in the base class and returns null.

It works well if I select some Values in the box and hit my save Button - in my model, I receive the correct enum value. But it doesn't work in the other direction - if i set any enum value (with or without flags) to my property, all values are unchecked and the content area is empty.

Do you have any idea to solve this problem?
Developer
Mar 16, 2016 at 1:16 PM
Hi,
In your ResolveValueBinding method, you bind to Editor.SelectedValue AND Editor.SelectedItem. The 2nd one cause an overflow exception, so I removed it.
To make your sample work, you need to call Editor.EndInit() when the initialization is done to update the CheckComboBox.SelectedValue. This is usually called by default, but here, the CheckComboBox is not used in a DataTemplate. So you can call it. Here's your modified ResolveValueBinding :
protected override void ResolveValueBinding( PropertyItem propertyItem )
      {
        var _binding = new Binding( "Value" );
        _binding.Source = propertyItem;
        _binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        _binding.Mode = BindingMode.TwoWay;
        _binding.Converter = CreateValueConverter();
        BindingOperations.SetBinding( Editor, CheckComboBox.SelectedValueProperty, _binding ); // or BindingOperations.SetBinding( Editor, ValueProperty, _binding );

        //var _binding2 = new Binding( "Value" );
        //_binding2.Source = propertyItem;
        //_binding2.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        //_binding2.Mode = BindingMode.TwoWay;
        //_binding2.Converter = CreateValueConverter();
        //BindingOperations.SetBinding( Editor, CheckComboBox.SelectedItemProperty, _binding2 );

        Editor.ItemsSource = Enum.GetValues( propertyItem.Value.GetType() );
        Editor.Initialized += Editor_Initialized;
      }

      private void Editor_Initialized( object sender, EventArgs e )
      {
        Editor.EndInit();
      }
Mar 16, 2016 at 4:11 PM
Hi,

Thanks for your help.

I try now to check three items Test 1, Test 2 and Test3. After i click my save button and see that all values are saved in my config file i reload PropertyGrid but only the first item is checked and displayed in the Editor.

Debug in ResolveValueBinding

propertyItem.Value = Value = (Core.Plugin.TestEnum.Test1 | Core.Plugin.TestEnum.Test2 | Core.Plugin.TestEnum.Test3) Typ = object{Core.Plugin.TestEnum}

What i have to do to see all saved value as checked and displayed in Editor.

Thank you.

Paul.
Developer
Mar 16, 2016 at 7:42 PM
Hi,

2 things.

1) Make sure your enum has the [Flags] attribute.

2) CheckComboBox.SelectedValue is a string of all the selectedItems separated by comma. Ex :
"Test2,Test3,Test4"
The EnumConverter.ConvertTo() method will convert "Test2 | Test3 | Test4" to
"Test2, Test3, Test4"
(note the spaces after the comma, which CheckComboBox.SelectedValue don't like).
You can use the ValueConverter in your CheckComboBoxEditor to remove those spaces :
 protected override IValueConverter CreateValueConverter()
      {
        return new MyConverter();
      }
where MyConverter is :
 public class MyConverter : IValueConverter
    {
      public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
      {
        if( value == null )
          return null;

        var stringEnumValues = TypeDescriptor.GetConverter( value ).ConvertTo( value, typeof( string ) ) as string;
        return stringEnumValues.Replace( " ", string.Empty );
      }

      public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
      {
        if( value == null )
          return null;
        
        return TypeDescriptor.GetConverter( value ).ConvertFrom( value ) as string;
      }
    }
Mar 17, 2016 at 9:45 AM
Hi,

Thanks for great support. It works fine.

Now i have following situation.

I have some data in my Database witch i want to make available in the CheckComboBox.

I create new Dictionary<int, CheckListBoxEntry>(); and add each record from my query.

The CheckListBoxEntry;
[DataContract]
public class CheckListBoxEntry : INotifyPropertyChanged
{
    public CheckListBoxEntry(bool isChecked, string displayText)
    {
        IsChecked = isChecked;
        DisplayText = displayText;
    }
    private bool _isChecked;
    [DataMember]
    public bool IsChecked
    {
        get { return _isChecked; }
        set
        {
            _isChecked = value;
            RaisePropertyChanged("IsChecked");
        }
    }

    [DataMember]
    [ExcludeFromSerialization]
    public string DisplayText { get; set; }

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
now CheckComboBoxEditor class:

i must change to:
BindingOperations.SetBinding(Editor, CheckComboBox.ItemsSourceProperty, _binding);
instead of:
BindingOperations.SetBinding(Editor, CheckComboBox.SelectedValueProperty, _binding);

because CheckComboBox hast red border and there are no items.


i use Editor.DisplayMemberPath = "Value.DisplayText";. Then i can see den right name of the Record e.g Demo1 , Demo2 ... when i open drop-down-list.

When i Check one Item I see this in the Editor textbox: [1,Core.Editor.CheckListBoxEntry] .....

After reload PropertyGrid all values are unchecked and the content area is empty.

I not sure what i have to change in the class MyConverter.

Can you please help me again.

Thanks a lot.

Paul
Developer
Mar 21, 2016 at 7:05 PM
Hi,

This looks like a different problem. You are not using the dynamic enum anymore, but a Dictionary. In v3.0, the propertyGrid will support the Dictionary type property and use the CollectionEditor to edit this property.
If you want to use the CheckComboBox for Dictionaries, here's the CheckComboBoxEditor that could work :
public class CheckComboBoxEditor : TypeEditor<CheckComboBox>, ITypeEditor
    {
      protected override void SetValueDependencyProperty()
      {
         ValueProperty = CheckComboBox.ItemsSourceProperty;
      }

      protected override void SetControlProperties( PropertyItem propertyItem )
      {
        Editor.DisplayMemberPath = "Value.DisplayText";
        Editor.SelectedMemberPath = "Value.IsChecked";
        base.SetControlProperties( propertyItem );
      }

      protected override CheckComboBox CreateEditor()
      {
        return new CheckComboBox();
      }

      protected override void ResolveValueBinding( PropertyItem propertyItem )
      {
        var _binding = new Binding( "Value" );
        _binding.Source = propertyItem;
        _binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        _binding.Mode = BindingMode.TwoWay;
        _binding.Converter = CreateValueConverter();
        BindingOperations.SetBinding( Editor, ValueProperty, _binding );

        Editor.Initialized += Editor_Initialized;
      }

      private void Editor_Initialized( object sender, EventArgs e )
      {
        Editor.EndInit();
      }
    }
BUT...
There is a problem with nested PropertyItems : they are not working. "Value.IsChecked" won't be found. Issue https://wpftoolkit.codeplex.com/workitem/22216 has been created.