我写了这个枚举(标志):
using System;
namespace AndreyBushman.AutoCAD {
// Specifies, how and when .NET application will load.
// It is a flag.
[Flags]
public enum LoadCtrls {
// Load application upon detection of proxy object
AtProxyFound = 1,
// Load the application at startup
AtAutoCADStart = 2,
// Load the application at start of a command
AtCommandStart = 4,
// Load the application at the request of a user
// or another application
AtUserOrApplicationRequirement = 8,
// Do not load the application
NotLoad = 16,
// Load the application transparently
TransparencyLoad = 32,
}
}
现在我已使用StackPanel
项创建了CheckBox
:
<StackPanel x:Name="stackAllUsersLoadCtrls">
<CheckBox Margin="2">At proxy found</CheckBox>
<CheckBox Margin="2">At AutoCAD start</CheckBox>
<CheckBox Margin="2">At command start</CheckBox>
<CheckBox Margin="2">At user or application requirement</CheckBox>
<CheckBox Margin="2">Not load</CheckBox>
<CheckBox Margin="2">Transparency load</CheckBox>
</StackPanel>
结果屏幕:
如何将LoadCtrls
的实例(它是标志)与CheckBox
项绑定?
UPD 的 我重写了我的代码(添加了包装器,重写转换器和XAML):
打包机:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ab = AndreyBushman.AutoCAD;
using System.ComponentModel;
namespace AcadLoadManaged {
public sealed class LoadCtrlsWrapper : INotifyPropertyChanged {
ab.LoadCtrls loadCtrls;
public ab.LoadCtrls GetloadCtrls() {
return loadCtrls;
}
public LoadCtrlsWrapper() {
loadCtrls = default(ab.LoadCtrls);
}
public LoadCtrlsWrapper(ab.LoadCtrls loadCtrls) {
this.loadCtrls = loadCtrls;
}
public Boolean AtAutoCADStart {
get {
return (loadCtrls & ab.LoadCtrls.AtAutoCADStart) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.AtAutoCADStart;
else
loadCtrls &= ~ab.LoadCtrls.AtAutoCADStart;
OnPropertyChanged("AtAutoCADStart");
}
}
public Boolean AtCommandStart {
get {
return (loadCtrls & ab.LoadCtrls.AtCommandStart) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.AtCommandStart;
else
loadCtrls &= ~ab.LoadCtrls.AtCommandStart;
OnPropertyChanged("AtCommandStart");
}
}
public Boolean AtProxyFound {
get {
return (loadCtrls & ab.LoadCtrls.AtProxyFound) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.AtProxyFound;
else
loadCtrls &= ~ab.LoadCtrls.AtProxyFound;
OnPropertyChanged("AtProxyFound");
}
}
public Boolean AtUserOrApplicationRequirement {
get {
return (loadCtrls & ab.LoadCtrls.AtUserOrApplicationRequirement) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.AtUserOrApplicationRequirement;
else
loadCtrls &= ~ab.LoadCtrls.AtUserOrApplicationRequirement;
OnPropertyChanged("AtUserOrApplicationRequirement");
}
}
public Boolean NotLoad {
get {
return (loadCtrls & ab.LoadCtrls.NotLoad) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.NotLoad;
else
loadCtrls &= ~ab.LoadCtrls.NotLoad;
OnPropertyChanged("NotLoad");
}
}
public Boolean TransparencyLoad {
get {
return (loadCtrls & ab.LoadCtrls.TransparencyLoad) != 0;
}
set {
if (value)
loadCtrls |= ab.LoadCtrls.TransparencyLoad;
else
loadCtrls &= ~ab.LoadCtrls.TransparencyLoad;
OnPropertyChanged("TransparencyLoad");
}
}
void OnPropertyChanged(String propertyName) {
PropertyChangedEventHandler temp = PropertyChanged;
if (null != temp)
temp(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
转换器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using ab = AndreyBushman.AutoCAD;
namespace AcadLoadManaged {
public sealed class LoadCtrlsConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) {
ab.LoadCtrls x = (ab.LoadCtrls)value;
return new LoadCtrlsWrapper(x);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) {
LoadCtrlsWrapper x = (LoadCtrlsWrapper)value;
return x.GetloadCtrls();
}
}
}
XAML:
<GroupBox Grid.Row="4" Header="Load this plugin, when...:" Grid.Column="0"
Grid.ColumnSpan="2" Padding="3">
<GroupBox.DataContext>
<Binding ElementName="lstAllUsers" Path="SelectedItem.LoadCtrls" Mode="TwoWay">
<Binding.Converter>
<local:LoadCtrlsConverter/>
</Binding.Converter>
</Binding>
</GroupBox.DataContext>
<StackPanel>
<CheckBox Margin="2" Content="At proxy found" IsChecked="{Binding Path=AtProxyFound}"/>
<CheckBox Margin="2" Content="At AutoCAD start" IsChecked="{Binding Path=AtAutoCADStart}"/>
<CheckBox Margin="2" Content="At command start" IsChecked="{Binding Path=AtCommandStart}"/>
<CheckBox Margin="2" Content="At user or application requirement"
IsChecked="{Binding Path=AtUserOrApplicationRequirement}"/>
<CheckBox Margin="2" Content="Not load" IsChecked="{Binding Path=NotLoad}"/>
<CheckBox Margin="2" Content="Transparency load" IsChecked="{Binding Path=TransparencyLoad}"/>
</StackPanel>
</GroupBox>
但我的绑定只有一种方式。如果我修改CheckBox
值 - 它们不会保存。我在ConvertBack
方法上尝试过断点,但它没有发生。为什么呢?
答案 0 :(得分:1)
有类似的需求,这是我的TwoWay标志绑定的方法。 没有硬编码的枚举类型或任何类型的值。只需设置TargetType和Flags即可。很棒的设置窗口。
用法:
<TextBox Text="{Binding ElementName=flagsCtrl, Path=Flags, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<local:FlagsControl x:Name="flagsCtrl" TargetType="{x:Type local:TestFlags}" SelectionMode="Multiple"/>
FlagsControl:
using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace FlagsControlDemoApplication
{
public class FlagsControl : ItemsControl
{
public FlagsControl()
{
Loaded += OnControlLoaded;
}
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnControlLoaded;
Binding isCheckedBinding = new Binding();
isCheckedBinding.Path = new PropertyPath(Model.IsCheckedProperty);
isCheckedBinding.Mode = BindingMode.TwoWay;
isCheckedBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
Binding nameBinding = new Binding();
nameBinding.Path = new PropertyPath(Model.NameProperty);
nameBinding.Mode = BindingMode.TwoWay;
nameBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
var checkBoxFactory = new FrameworkElementFactory(typeof(CheckBox));
checkBoxFactory.SetValue(CheckBox.IsCheckedProperty, isCheckedBinding);
checkBoxFactory.SetValue(CheckBox.ContentProperty, nameBinding);
checkBoxFactory.AddHandler(CheckBox.CheckedEvent, new RoutedEventHandler(OnCheckBoxChecked));
checkBoxFactory.AddHandler(CheckBox.UncheckedEvent, new RoutedEventHandler(OnCheckBoxUnchecked));
ItemTemplate = new DataTemplate(typeof(CheckBox));
ItemTemplate.VisualTree = checkBoxFactory;
ItemsSource = DataProvider;
}
public FlagSelectionMode SelectionMode
{
get { return (FlagSelectionMode)GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
public static readonly DependencyProperty SelectionModeProperty =
DependencyProperty.Register(nameof(SelectionMode), typeof(FlagSelectionMode), typeof(FlagsControl), new PropertyMetadata(FlagSelectionMode.Multiple));
public ObservableCollection<Model> DataProvider
{
get { return (ObservableCollection<Model>)GetValue(DataProviderProperty); }
set { SetValue(DataProviderProperty, value); }
}
public static readonly DependencyProperty DataProviderProperty =
DependencyProperty.Register(nameof(DataProvider), typeof(ObservableCollection<Model>), typeof(FlagsControl), new PropertyMetadata(new ObservableCollection<Model>()));
public uint Flags
{
get { return (uint)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Flags), typeof(uint), typeof(FlagsControl), new PropertyMetadata(OnValuePropertyChanged));
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
foreach (var model in ((FlagsControl)d).DataProvider)
{
var val = (uint)Convert.ChangeType(e.NewValue, typeof(uint));
if (Exists(val, model.Value) != model.IsChecked)
{
model.IsChecked = !model.IsChecked;
}
}
}
public Type TargetType
{
get { return (Type)GetValue(TargetTypeProperty); }
set { SetValue(TargetTypeProperty, value); }
}
public static readonly DependencyProperty TargetTypeProperty =
DependencyProperty.Register(nameof(TargetType), typeof(Type), typeof(FlagsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnTargetTypePropertyChanged)));
private static void OnTargetTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var provider = ((FlagsControl)d).DataProvider;
FieldInfo[] fields = ((Type)e.NewValue).GetFields(BindingFlags.Public | BindingFlags.Static);
provider.Clear();
foreach (var field in fields)
{
var fieldValue = (uint)Convert.ChangeType(field.GetValue(null), typeof(uint));
provider.Add(new Model() { Name = field.Name, IsChecked = Exists(((FlagsControl)d).Flags, fieldValue), Value = fieldValue });
}
((FlagsControl)d).DataProvider = provider;
}
private void OnCheckBoxChecked(object sender, RoutedEventArgs e)
{
if (SelectionMode == FlagSelectionMode.Multiple)
Flags = Add(Flags, ((Model)((CheckBox)sender).DataContext).Value);
else Flags = ((Model)((CheckBox)sender).DataContext).Value;
}
private void OnCheckBoxUnchecked(object sender, RoutedEventArgs e)
{
Flags = Remove(Flags, ((Model)((CheckBox)sender).DataContext).Value);
}
public static bool Exists(uint flags, uint flag) => (flags & flag) == flag;
public static uint Add(uint flags, uint flag) => flags |= flag;
public static uint Remove(uint flags, uint flag) => Exists(flags, flag) ? flags ^ flag : flags;
}
public enum FlagSelectionMode
{
Multiple, Single
}
public class Model : DependencyObject
{
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(nameof(IsChecked), typeof(bool), typeof(Model));
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register(nameof(Name), typeof(string), typeof(Model));
public uint Value
{
get { return (uint)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(uint), typeof(Model));
}
}
答案 1 :(得分:0)
要使Model
(LoadCtrls)适应View
(XAML),请使用ViewModel
。
public class ApplicationSettingsViewModel :
MyViewModelBaseImplementingINotifyPropertyChanged {
public ApplicationSettingsViewModel(ApplicationSettings model)
{
m_model = model;
m_model.PropertyChanged += OnModelPropertyChanged;
}
... OnModelPropertyChanged(object sender, WhateverArgs e)
{
switch(e.PropertyName)
{
...
case "Load":
RaisePropertyChanged("IsAtProxyFoundSet");
RaisePropertyChanged("IsAtAutoCADStartSet");
...
break;
...
}
}
...
public bool IsAtProxyFoundSet
{
get { return m_model.Load & LoadCtrls.AtProxyFound; }
set { m_model.Load |= LoadCtrls.AtProxyFound; }
}
public bool IsAtAutoCADStartSet
{
get { return m_model.Load & LoadCtrls.AtAutoCADStart; }
set { m_model.Load |= LoadCtrls.AtAutoCADStart; }
}
...
}
<强>更新强>
这是一个更新的例子:
public sealed class UserWrapper {
private User m_user;
public UserWrapper(User user) {
m_user = user;
}
public Boolean AtAutoCADStart {
get {
return (m_user.loadCtrls & ab.LoadCtrls.AtAutoCADStart) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.AtAutoCADStart;
else
m_user.loadCtrls &= ~ab.LoadCtrls.AtAutoCADStart;
}
}
public Boolean AtCommandStart {
get {
return (m_user.loadCtrls & ab.LoadCtrls.AtCommandStart) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.AtCommandStart;
else
m_user.loadCtrls &= ~ab.LoadCtrls.AtCommandStart;
}
}
public Boolean AtProxyFound {
get {
return (m_user.loadCtrls & ab.LoadCtrls.AtProxyFound) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.AtProxyFound;
else
m_user.loadCtrls &= ~ab.LoadCtrls.AtProxyFound;
}
}
public Boolean AtUserOrApplicationRequirement {
get {
return (m_user.loadCtrls & ab.LoadCtrls.AtUserOrApplicationRequirement) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.AtUserOrApplicationRequirement;
else
m_user.loadCtrls &= ~ab.LoadCtrls.AtUserOrApplicationRequirement;
}
}
public Boolean NotLoad {
get {
return (m_user.loadCtrls & ab.LoadCtrls.NotLoad) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.NotLoad;
else
m_user.loadCtrls &= ~ab.LoadCtrls.NotLoad;
}
}
public Boolean TransparencyLoad {
get {
return (m_user.loadCtrls & ab.LoadCtrls.TransparencyLoad) != 0;
}
set {
if (value)
m_user.loadCtrls |= ab.LoadCtrls.TransparencyLoad;
else
m_user.loadCtrls &= ~ab.LoadCtrls.TransparencyLoad;
}
}
}
转换器:
public sealed class UserToUserWrapperConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) {
return new UserWrapper((User)value);
}
public object ConvertBack(object value, Type targetType, object parameter,
throw new Exception(); // never called
}
}
}
XAML:
<GroupBox Grid.Row="4" Header="Load this plugin, when...:" Grid.Column="0"
Grid.ColumnSpan="2" Padding="3">
<GroupBox.DataContext>
<Binding ElementName="lstAllUsers" Path="SelectedItem">
<Binding.Converter>
<local:UserToUserWrapperConverter/>
</Binding.Converter>
</Binding>
</GroupBox.DataContext>
<StackPanel>
<CheckBox Margin="2" Content="At proxy found" IsChecked="{Binding Path=AtProxyFound}"/>
<CheckBox Margin="2" Content="At AutoCAD start" IsChecked="{Binding Path=AtAutoCADStart}"/>
<CheckBox Margin="2" Content="At command start" IsChecked="{Binding Path=AtCommandStart}"/>
<CheckBox Margin="2" Content="At user or application requirement"
IsChecked="{Binding Path=AtUserOrApplicationRequirement}"/>
<CheckBox Margin="2" Content="Not load" IsChecked="{Binding Path=NotLoad}"/>
<CheckBox Margin="2" Content="Transparency load" IsChecked="{Binding Path=TransparencyLoad}"/>
</StackPanel>
</GroupBox>
答案 2 :(得分:0)
我使用自定义复选框并绑定2个属性,因为枚举标志与其枚举值之间存在依赖关系。
这是我的代码(我在生产中成功使用它并且使用起来非常简单 - 请参阅课程顶部的评论)。
你喜欢吗?using System;
using System.Windows;
using System.Windows.Controls;
namespace HQ.Wpf.Util.MyControl
{
/// <summary>
/// Usage: Bind on EnumFlag and Two way binding on EnumValue instead of IsChecked
/// Example: <myControl:CheckBoxForEnumWithFlagAttribute
/// EnumValue="{Binding SimulationNatureTypeToCreateStatsCacheAtEndOfSimulation, Mode=TwoWay}"
/// EnumFlag="{x:Static Core:SimulationNatureType.LoadFlow }">Load Flow results</myControl:CheckBoxForEnumWithFlagAttribute>
/// </summary>
public class CheckBoxForEnumWithFlagAttribute : CheckBox
{
// ************************************************************************
public static DependencyProperty EnumValueProperty =
DependencyProperty.Register("EnumValue", typeof(object), typeof(CheckBoxForEnumWithFlagAttribute), new PropertyMetadata(EnumValueChangedCallback));
public static DependencyProperty EnumFlagProperty =
DependencyProperty.Register("EnumFlag", typeof(object), typeof(CheckBoxForEnumWithFlagAttribute), new PropertyMetadata(EnumFlagChangedCallback));
// ************************************************************************
public CheckBoxForEnumWithFlagAttribute()
{
base.Checked += CheckBoxForEnumWithFlag_Checked;
base.Unchecked += CheckBoxForEnumWithFlag_Unchecked;
}
// ************************************************************************
private static void EnumValueChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var checkBoxForEnumWithFlag = dependencyObject as CheckBoxForEnumWithFlagAttribute;
if (checkBoxForEnumWithFlag != null)
{
checkBoxForEnumWithFlag.RefreshCheckBoxState();
}
}
// ************************************************************************
private static void EnumFlagChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var checkBoxForEnumWithFlag = dependencyObject as CheckBoxForEnumWithFlagAttribute;
if (checkBoxForEnumWithFlag != null)
{
checkBoxForEnumWithFlag.RefreshCheckBoxState();
}
}
// ************************************************************************
public object EnumValue
{
get { return GetValue(EnumValueProperty); }
set { SetValue(EnumValueProperty, value); }
}
// ************************************************************************
public object EnumFlag
{
get { return GetValue(EnumFlagProperty); }
set { SetValue(EnumFlagProperty, value); }
}
// ************************************************************************
private void RefreshCheckBoxState()
{
if (EnumValue != null)
{
if (EnumValue is Enum)
{
Type underlyingType = Enum.GetUnderlyingType(EnumValue.GetType());
dynamic valueAsInt = Convert.ChangeType(EnumValue, underlyingType);
dynamic flagAsInt = Convert.ChangeType(EnumFlag, underlyingType);
base.IsChecked = ((valueAsInt & flagAsInt) > 0);
}
}
}
// ************************************************************************
private void CheckBoxForEnumWithFlag_Checked(object sender, RoutedEventArgs e)
{
RefreshEnumValue();
}
// ************************************************************************
void CheckBoxForEnumWithFlag_Unchecked(object sender, RoutedEventArgs e)
{
RefreshEnumValue();
}
// ************************************************************************
private void RefreshEnumValue()
{
if (EnumValue != null)
{
if (EnumValue is Enum)
{
Type underlyingType = Enum.GetUnderlyingType(EnumValue.GetType());
dynamic valueAsInt = Convert.ChangeType(EnumValue, underlyingType);
dynamic flagAsInt = Convert.ChangeType(EnumFlag, underlyingType);
dynamic newValueAsInt = valueAsInt;
if (base.IsChecked == true)
{
newValueAsInt = valueAsInt | flagAsInt;
}
else
{
newValueAsInt = valueAsInt & ~flagAsInt;
}
if (newValueAsInt != valueAsInt)
{
object o = Enum.ToObject(EnumValue.GetType(), newValueAsInt);
EnumValue = o;
}
}
}
}
// ************************************************************************
}
}