当前位置: 首页 > 编程语言 > C#

如何将复选框双向绑定到标志枚举的单个位?Share

时间:2023-04-10 22:54:35 C#

如何将复选框双向绑定到标志枚举的单个位?对于喜欢WPF绑定挑战的任何人:我有一个将复选框双向绑定到标志枚举的单个位的近功能示例(感谢IanOakes,原始MSDN帖子)。但问题是绑定的行为就好像它是一种方式(UI到DataContext,反之亦然)。所以复选框不会初始化,但如果切换,数据源会正确更新。Attached是一个类,它定义了一些附加的依赖属性以启用基于位的绑定。我注意到的是,即使我强制更改DataContext,也永远不会调用ValueChanged。我尝试过:更改属性定义的顺序,使用标签和文本框确认DataContext正在冒泡更新,任何合理的FrameworkMetadataPropertyOptions(AffectsRender,BindsTwoWayByDefault),显式设置BindingMode=TwoWay,敲墙,在发生冲突时更改ValueProperty到枚举值属性。任何建议或想法将不胜感激,谢谢!枚举:[Flags]publicenumDepartment:byte{None=0x00,A=0x01,B=0x02,C=0x04,D=0x08}//endenumDepartmentXAMLusage:CheckBoxName="studentIsInDeptACheckBox"ctrl:CheckBoxFlagsBehaviour.Mask="{x:Staticc:Department.A}"ctrl:CheckBoxFlagsBehaviour.IsChecked="{BindingPath=IsChecked,RelativeSource={RelativeSourceSelf}}"ctrl:CheckBoxFlagsBehaviour.Value="{BindingDepartment}"类://////用于提供按位绑定的辅助类。///公共类CheckBoxFlagsBehaviour{privatestaticboolisValueChanging;publicstaticEnumGetMask(DependencyObjectobj){return(Enum)obj.GetValue(MaskProperty);}//结束GetMaskpublicstaticvoidSetMask(DependencyObjectobj,Enumvalue){obj.SetValue(MaskProperty,value);}//结束SetMaskpublicstaticreadonlyDependencyPropertyMaskProperty=DependencyProperty.RegisterAttached("Mask",typeof(Enum),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(无效的));publicstaticEnumGetValue(DependencyObjectobj){return(Enum)obj.GetValue(ValueProperty);}//结束GetValuepublicstaticvoidSetValue(DependencyObjectobj,Enumvalue){obj.SetValue(ValueProperty,value);}//结束SetValuepublicstaticreadonlyDependencyPropertyValueProperty=DependencyProperty.RegisterAttached("Value",typeof(Enum),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(null,ValueChanged));privatestaticvoidValueChanged(DependencyObjectd,DependencyPropertyChangedEventArgse){isValueChanging=true;字节掩码=Convert.ToByte(GetMask(d));字节值=Convert.ToByte(e.NewValue);BindingExpressionexp=BindingOperations.GetBindingExpression(d,IsCheckedProperty);objectdataItem=GetUnderlyingDataItem(exp.DataItem);PropertyInfopi=dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);pi.SetValue(dataItem,(value&mask)!=0,null);((CheckBox)d).IsChecked=(value&mask)!=0;值ueChanging=假;}//结束ValueChangedpublicstaticbool?GetIsChecked(DependencyObjectobj){return(bool?)obj.GetValue(IsCheckedProperty);}//结束GetIsCheckedpublicstaticvoidSetIsChecked(DependencyObjectobj,bool?value){obj.SetValue(IsCheckedProperty,value);}//结束SetIsCheckedpublicstaticreadonlyDependencyPropertyIsCheckedProperty=DependencyProperty.RegisterAttached("IsChecked",typeof(bool?),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(false,IsCheckedChanged));privatestaticvoidIsCheckedChanged(DependencyObjectd,DependencyPropertyChangedEventArgse){if(isValueChanging)返回;布尔?isChecked=(bool?)e.NewValue;if(isChecked!=null){BindingExpressionexp=BindingOperations.GetBindingExpression(d,ValueProperty);objectdataItem=GetUnderlyingDataItem(exp.DataItem);PropertyInfopi=dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);字节掩码=Convert.ToByte(GetMask(d));字节值e=Convert.ToByte(pi.GetValue(dataItem,null));if(isChecked.Value){if((value&mask)==0){value=(byte)(value+mask);}}else{if((value&mask)!=0){value=(byte)(value-mask);}}pi.SetValue(dataItem,value,null);}}//endIsCheckedChanged//////从对象获取基础数据项。//////要检查的对象。///底层数据项(如果合适)或传入的对象。privatestaticobjectGetUnderlyingDataItem(objecto){returnoisDataRowView?((DataRowView)o).行:o;}//endGetUnderlyingDataItem}//endclassCheckBoxFlagsBehaviour您可以使用值转换器这是目标枚举的一个非常具体的实现,但不难看出如何使转换器更通用:[Flags]publicenumDepartment{None=0,A=1,B=2,C=4,D=8}publicpartialclassWindow1:Window{publicWindow1(){InitializeComponent();this.DepartmentsPanel.DataContext=newDataObject{Department=Department.A|部门.C};}}publicclassDataObject{publicDataObject(){}publicDepartmentDepartment{get;放;}}publicclassDepartmentValueConverter:IValueConverter{privateDepartmenttarget;publicDepartmentValueConverter(){}publicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){Departmentmask=(Department)parameter;this.target=(Department)value;return((mask&this.target)!=0);}publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){this.target^=(Department)parameter;返回这个目标;然后在XAML中使用转换器:编辑:我没有足够的“代表”(还!)在下面发表评论所以我必须更新我自己的帖子:(在最后一条评论中,demwiz.myopenid.com说“但是在双向绑定时ConvertBack会崩溃”,我已经更新了上面的示例代码来处理ConvertBack场景;我还在此处发布了一个示例工作应用程序(编辑:注意,示例代码下载还包括转换器的通用版本)我个人认为这更简单,我希望这会有所帮助。谢谢大家的帮助,我终于弄明白了。我绑定到强类型数据集,因此枚举存储为System.Byte类型而不是System.Enum。我碰巧在我的调试输出窗口中发现了一个指向这种差异的静默绑定转换异常。解决方法同上,只是ValueProperty的类型不是Enum,而是Byte。这是在最终修订版中复制的CheckBoxFlagsBehavior类。再次感谢IanOakes的最初实现!publicstaticEnumGetMask(DependencyObjectobj){return(Enum)obj.GetValue(MaskProperty);}//结束GetMaskpublicstaticvoidSetMask(DependencyObjectobj,Enumvalue){obj.SetValue(MaskProperty,value);}//结束SetMaskpublicstaticreadonlyDependencyPropertyMaskProperty=DependencyProperty.RegisterAttached("Mask",typeof(Enum),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(null));publicstaticbyteGetValue(DependencyObjectobj){return(byte)obj.GetValue(ValueProperty);}//结束GetValuepublicstaticvoidSetValue(DependencyObjectobj,bytevalue){obj.SetValue(ValueProperty,value);}//结束SetValuepublicstaticreadonlyDependencyPropertyValueProperty=DependencyProperty.RegisterAttached("Value",typeof(byte),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(default(byte),ValueChanged));私有静态无效ValueChanged(DependencyObjectd,DependencyPropertyChangedEventArgse){isValueChanging=true;字节掩码=Convert.ToByte(GetMask(d));字节值=Convert.ToByte(e.NewValue);BindingExpressionexp=BindingOperations.GetBindingExpression(d,IsCheckedProperty);objectdataItem=GetUnderlyingDataItem(exp.DataItem);PropertyInfopi=dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);pi.SetValue(dataItem,(value&mask)!=0,null);((CheckBox)d).IsChecked=(value&mask)!=0;isValueChanging=false;}//结束ValueChangedpublicstaticbool?GetIsChecked(DependencyObjectobj){return(bool?)obj.GetValue(IsCheckedProperty);}//结束GetIsCheckedpublicstaticvoidSetIsChecked(DependencyObjectobj,bool?value){obj.SetValue(IsCheckedProperty,value);}//结束SetIsCheckedpublicstaticreadonlyDependencyPropertyIsCheckedProperty=DependencyProperty.RegisterAttached("IsChecked",typeof(bool?),typeof(CheckBoxFlagsBehaviour),newUIPropertyMetadata(false,IsCheckedChanged));privatestaticvoidIsCheckedChanged(DependencyObjectd,DependencyPropertyChangedEventArgse){if(isValueChanging)返回;布尔?isChecked=(bool?)e.NewValue;if(isChecked!=null){BindingExpressionexp=BindingOperations.GetBindingExpression(d,ValueProperty);objectdataItem=GetUnderlyingDataItem(exp.DataItem);PropertyInfopi=dataItem.GetType().GetProperty(exp.ParentBinding.Path.Path);字节掩码=Convert.ToByte(GetMask(d));字节值=Convert.ToByte(pi.GetValue(dataItem,null));if(isChecked.Value){if((value&mask)==0){value=(byte)(value+mask);}}else{if((value&mask)!=0){value=(byte)(value-mask);}}pi.SetValue(dataItem,value,null);}}//endIsCheckedChangedprivatestaticobjectGetUnderlyingDataItem(objecto){返回o是DataRowView吗?((DataRowView)o).行:o;}//endGetUnderlyingDataItem}//endclassCheckBoxFlagsBehaviour检查绑定到包含Department属性的CheckBoxes的DataObject是否在其Setter上调用了INotifyPropertyChnaged.PropertyChanged?这是我想出的让视图看起来干净整洁的东西(不需要静态资源,不需要填充新的附加属性,绑定中不需要转换器或转换器参数),并保持ViewModelA干净(不需要绑定额外的属性to)View看起来像这样:ViewModel看起来像这样:publicclassViewModel:ViewModelBase{privateDepartmentdepartment;publicViewModel(){Department=newEnumFlags(department);}publicDepartmentDepartment{get;私有集;如果您要为Department属性分配一个新值,请不要对department置之不理。将新值写入Department.Value。这就是魔法发生的地方(这个泛型类可以重复用于任何标志枚举)上面是C#学习教程:如何将复选框双向绑定到标志枚举的单个位?分享的所有内容,如果对你有用,需要了解更多C#学习教程,希望你多多关注——publicclassEnumFlags:INotifyPropertyChangedwhereT:struct,IComparable,IFormattable,IConvertible{privateT价值;publicEnumFlags(Tt){if(!typeof(T).IsEnum)thrownewArgumentException($"{nameof(T)}必须是枚举类型");//我真的希望他们能让我将枚举添加到泛型类型约束中value=t;}publicTValue{get{返回值;}设置{如果(this.value.Equals(value))返回;this.value=值;OnPropertyChanged("物品[]");}}[IndexerName("Item")]publicboolthis[Tkey]{get{//.net不允许我们指定T是一个枚举,所以它认为我们不能将T转换为int。//为了解决这个问题,先将其转换为对象,然后再将其转换为int。返回(((int)(对象)值&(int)(对象)键)==(int)(对象)键);}set{if((((int)(object)this.value&(int)(object)key)==(int)(object)key)==v价值)回报;this.value=(T)(object)((int)(object)this.value^(int)(object)key);OnPropertyChanged("物品[]");}}#regionINotifyPropertyChanged公共事件PropertyChangedEventHandlerPropertyChanged;privatevoidOnPropertyChanged([CallerMemberName]stringmemberName=""){PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(memberName));}#endregion}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:

最新推荐
猜你喜欢