WPF MVVM中的绑定复选框问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF MVVM中的绑定复选框问题相关的知识,希望对你有一定的参考价值。
我在从VM获取复选框IsChecked绑定值的值时遇到问题。 (我正在使用MVVM Light)。
我的问题:当复选框IsChecked被更改时,它不会回复到我绑定到的VM属性。
下面是代码。
我有一个带有布尔值的类(在类文件中)。
public class Rights
{
public bool bSales { get; set; }
public bool bProduct { get; set; }
public bool bZone { get; set; }
public bool bPercentage { get; set; }
public bool bUser { get; set; }
}
这是我的复选框将绑定到的属性(在VM中)。
private Rights user_Rights;
public Rights User_Rights
{
get { return user_Rights; }
set { Set(ref user_Rights, value); }
}
以下是我的“全选”复选框(在VM中)的属性。
private bool? rights_All;
public bool? Rights_All
{
get { return rights_All; }
set
{
Set(ref rights_All, value);
if (value == true)
{
User_Rights = new Rights() { bSales = true, bProduct = true, bPercentage = true, bZone = true, bUser = true };
}
else if(value == false)
{
User_Rights = new Rights() { bSales = false, bProduct = false, bPercentage = false, bZone = false, bUser = false };
}
}
}
最后,下面是我绑定的XAML。
<CheckBox Content="Sales PIC" IsChecked="{Binding User_Rights.bSales,Mode=TwoWay}" />
<CheckBox Content="Product" IsChecked="{Binding User_Rights.bProduct,Mode=TwoWay}" />
<CheckBox Content="Zone" IsChecked="{Binding User_Rights.bZone,Mode=TwoWay}" />
<CheckBox Content="Percentage" IsChecked="{Binding User_Rights.bPercentage}" />
<CheckBox Content="User" IsChecked="{Binding User_Rights.bUser}" />
<CheckBox Content="Select All" IsChecked="{Binding Rights_All}" />
关于我哪里做错了的任何建议?谢谢。
我不知道你的viewmodel基类被调用了什么,所以我只使用了自己的。我不知道你的Set()
方法是如何工作的;这可能需要你的一点调整。那一定是你的工作;轮到你了。我这样写是因为向你解释逻辑比编写代码需要更长的时间。您应该阅读此代码并理解它,而不是简单地将其粘贴到您的项目中。
请注意,我使用传统的C#命名约定编写了这个。布尔属性不再具有b
前缀。这意味着您必须从XAML中绑定的路径中删除该前缀。
另请注意,我将Rights_All
重命名为All
,并将其移至另一个视图模型。它现在是Rights
视图模型的成员。这也需要更改绑定。
您应该考虑使用Flags
枚举作为您的权利。这将简化代码,并使将来更容易添加其他权限。
public class Rights : ViewModelBase
{
private bool _sales;
public bool Sales {
get { return _sales; }
set { SetRightFlag(ref _sales, value); }
}
private bool _product;
public bool Product
{
get { return _product; }
set { SetRightFlag(ref _product, value); }
}
private bool _zone;
public bool Zone
{
get { return _zone; }
set { SetRightFlag(ref _zone, value); }
}
private bool _percentage;
public bool Percentage
{
get { return _percentage; }
set { SetRightFlag(ref _percentage, value); }
}
private bool _user;
public bool User
{
get { return _user; }
set { SetRightFlag(ref _user, value); }
}
// This logic needs to happen in five different setters, so I put it in a
// method.
private bool SetRightFlag(ref bool field, bool value, [System.Runtime.CompilerServices.CallerMemberName] string propName = null)
{
if (field != value)
{
Set(ref field, value, propName);
UpdateAll();
return true;
}
return false;
}
// I made this its own method as well, for cleanliness and clarity, even though
// it's only called once.
protected void UpdateAll()
{
// Don't call the All setter from here, because it has side effects.
if (User && Percentage && Zone && Product && Sales)
{
_all = true;
OnPropertyChanged(nameof(All));
}
else if (!User && !Percentage && !Zone && !Product && !Sales)
{
_all = false;
OnPropertyChanged(nameof(All));
}
else if (All.HasValue)
{
_all = null;
OnPropertyChanged(nameof(All));
}
}
private bool? _all = null;
public bool? All
{
get { return _all; }
set {
if (_all != value)
{
Set(ref _all, value);
if (_all.HasValue)
{
User = Percentage = Zone = Product = Sales = (bool)_all;
}
}
}
}
}
以下是我的解决方案的答案(在得到@Ed Plunkett和@zaitsman的建议之后)我实现了INotifyProperty(通过使用MVVM Light方式)到我的模型中的一个类。
对于我的模型类。
public class Rights: ViewModelBase
{
public Rights()
{
_bSalesPIC = false;
_bZone = false;
... (etc)
_bAll = false;
}
private bool _bSalesPIC;
public bool bSalesPIC
{
get { return _bSalesPIC; }
set
{
Set(ref _bSalesPIC, value);
TriggerAll();
}
}
private bool _bZone;
public bool bZone
{
get { return _bZone; }
set
{
Set(ref _bZone, value);
TriggerAll();
}
}
private bool? _bAll;
public bool? bAll
{
get { return _bAll; }
set
{
Set(ref _bAll , value);
if (value == true)
{
_bSalesPIC = true;
_bZone = true;
RaisePropertyChanged("bSalesPIC");
RaisePropertyChanged("bZone");
}
else if (value == false)
{
_bSalesPIC = false;
_bZone = false;
RaisePropertyChanged("bSalesPIC");
RaisePropertyChanged("bZone");
}
}
}
private void TriggerAll()
{
if (_bSalesPIC && _bZone && etc)
bAll = true;
else if (!_bSalesPIC && !_bZone && etc)
bAll = false;
else
bAll = null;
}
对于我的VM。
private Rights user_Rights;
public Rights User_Rights
{
get { return user_Rights; }
set { Set(ref user_Rights, value); }
}
而对于我的观点(XAML)。
<CheckBox Content="Sales PIC" IsChecked="{Binding User_Rights.bSalesPIC}" />
<CheckBox Content="Sales Input" IsChecked="{Binding User_Rights.bSalesInput}" />
<CheckBox Content="Product" IsChecked="{Binding User_Rights.bProduct}" />
<CheckBox Content="Zone" IsChecked="{Binding User_Rights.bZone}" />
<CheckBox Content="Percentage" IsChecked="{Binding User_Rights.bPercentage}" />
<CheckBox Content="User" IsChecked="{Binding User_Rights.bUser}" />
<CheckBox Content="Select All" IsChecked="{Binding User_Rights.bAll}" />
以上是关于WPF MVVM中的绑定复选框问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 MVVM 绑定 WPF DataGridComboBoxColumn