2016-01-22 44 views
2

我使用Xceed Extended WPF Toolkit在PropertyGrid中顯示[Flags]屬性的枚舉。WPF Toolkit:CheckComboBox和[Flags] enum

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

因爲我不知道在編譯時枚舉定義,我會動態地創建使用EnumBuilder枚舉。

我創建了一個編輯器來顯示枚舉爲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()); 
    } 
} 

正如你所看到的,到目前爲止,我一直在努力,每個SelectedValueSelectedItem屬性綁定。 CreateValueConverter()在基類中定義並返回null

它運作良好,如果我選擇框中的一些值,並打我的保存按鈕 - 在我的模型中,我收到正確的枚舉值。但它不工作在其他方向 - 如果我設置任何枚舉值(帶或不帶標誌)到我的屬性,所有值都未選中,內容區域是

你有什麼想法來解決這個問題嗎?

回答

5

對於帶FlagsAttribute的枚舉,在這種情況下,最常用的解決方案是在虛擬機中爲Enum的所有項目和選定項目使用特定字段。類似的東西:

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 爲了使動態生成的枚舉,我做了以下修改的代碼工作:

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(); 
    } 
} 

爲ItemViewModel值可設定這樣的:

ItemViewModel vm = new ItemViewModel(); 
vm.Value = Enum.ToObject(ItemViewModel.EnumType, 33); 
+0

什麼我忘了說 - 對不起,我會更新我的問題 - 是我不能依靠一個編譯時枚舉。我會動態地使用'[EnumBuilder](https://msdn.microsoft.com/de-de/library/system.reflection.emit.enumbuilder%28v=vs.110%29.aspx)''創建'Enum'。 –

+0

更新了代碼以處理動態生成的帶有flags屬性的枚舉。 –