For Enum with FlagsAttribute in that case the most general solution would be to use specific fields in your VM for all items of the Enum and for selected items. Something like that:
XAML
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<xctkpg:PropertyGrid Grid.Row="1" SelectedObject="{Binding CurrentObject}" AutoGenerateProperties="False">
<xctkpg:PropertyGrid.EditorDefinitions>
<xctkpg:EditorTemplateDefinition TargetProperties="{x:Type local:TestEnum}">
<xctkpg:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<xctk:CheckComboBox ItemsSource="{Binding Instance.Items}" SelectedValue="{Binding Instance.SelValue}" />
</DataTemplate>
</xctkpg:EditorTemplateDefinition.EditingTemplate>
</xctkpg:EditorTemplateDefinition>
</xctkpg:PropertyGrid.EditorDefinitions>
<xctkpg:PropertyGrid.PropertyDefinitions>
<xctkpg:PropertyDefinition TargetProperties="Value" />
</xctkpg:PropertyGrid.PropertyDefinitions>
</xctkpg:PropertyGrid>
</Grid>
C#
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ItemViewModel _currentObject = new ItemViewModel() { Value = TestEnum.Test3 | TestEnum.Test7 };
public ItemViewModel CurrentObject
{
get { return _currentObject; }
set
{
_currentObject = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentObject)));
}
}
}
public class ItemViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private TestEnum _value;
public TestEnum Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelValue)));
}
}
public string SelValue
{
get
{
return String.Join(",", Enum.GetValues(typeof(TestEnum)).OfType<TestEnum>().Where(v => (_value & v) != 0).Select(v => v.ToString()));
}
set
{
_value = value.Split(new[] { ','}, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).
Aggregate((TestEnum)0, (acc, val) => acc | (TestEnum)Enum.Parse(typeof(TestEnum), val));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelValue)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
public ObservableCollection<string> Items
{
get
{
return new ObservableCollection<string>(Enum.GetNames(typeof(TestEnum)));
}
}
}
UPDATE 31/01/2016
To make the code work for dynamically generated Enum, I've made following changes:
XAML
<xctkpg:EditorTemplateDefinition TargetProperties="Value">
C#
public class ItemViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public static readonly Type EnumType = GenerateEnumType();
private object _value;
public object Value
{
get { return _value; }
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelValue)));
}
}
public string SelValue
{
get
{
return String.Join(",",
Enum.GetValues(EnumType).OfType<object>().Where(v => ((int)_value & (int)v) != 0).Select(v => v.ToString()));
}
set
{
var strings = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim());
_value = Enum.ToObject(EnumType, strings.Aggregate(0, (acc, val) => acc | (int)Enum.Parse(EnumType, val)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelValue)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
public ObservableCollection<string> Items
{
get
{
return new ObservableCollection<string>(Enum.GetNames(EnumType));
}
}
public static Type GenerateEnumType()
{
string asmNameString = "flags_enum";
// Create Base Assembly Objects
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName asmName = new AssemblyName(asmNameString);
AssemblyBuilder asmBuilder = appDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
// Create Module and Enumeration Builder Objects
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(asmNameString + "_module");
EnumBuilder enumBuilder = modBuilder.DefineEnum(asmNameString, TypeAttributes.Public, typeof(int));
Type fa = typeof(FlagsAttribute);
CustomAttributeBuilder attributeBuilder =
new CustomAttributeBuilder(fa.GetConstructor(new Type[0]), new object[0]);
enumBuilder.SetCustomAttribute(attributeBuilder);
for (int i = 0; i < 7; i++)
{
enumBuilder.DefineLiteral($"Test{i + 1}", 1 << i);
}
return enumBuilder.CreateType();
}
}
Now for ItemViewModel Value could be set like this:
ItemViewModel vm = new ItemViewModel();
vm.Value = Enum.ToObject(ItemViewModel.EnumType, 33);