简体   繁体   English

WPF MVVM中的绑定复选框问题

[英]Binding checkbox issue in WPF MVVM

I am facing a problem in getting the value from VM for checkbox IsChecked binding value. 我在从VM获取复选框IsChecked绑定值的值时遇到问题。 (I'm using MVVM Light). (我正在使用MVVM Light)。

My issue : When checkbox IsChecked is changed, it is not firing back to my VM property that I bind to. 我的问题 :更改复选框IsChecked时,它不会重新触发绑定到的VM属性。

Below is the code. 下面是代码。

I have a class with boolean values (in a class file). 我有一个带有布尔值的类(在类文件中)。

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

And this is the property that my checkboxes will bind to (in VM). 这是我的复选框将绑定到的属性(在VM中)。

private Rights user_Rights;
public Rights User_Rights
{
    get { return user_Rights; }
    set { Set(ref user_Rights, value); }
}

And below is the property for my 'Select All' check box (in VM). 以下是我的“全选”复选框(在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 };
        }
    }
}

And finally, below is my XAML for the binding. 最后,下面是绑定的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}" />

Here is what I am doing in picture. 这是我在图片中所做的。 在此处输入图片说明

Any suggestion on where did I do wrong? 关于我在哪里做错的任何建议? Thanks. 谢谢。

I don't know what your viewmodel base class is called, so I just used my own. 我不知道您的viewmodel基类是什么,所以我只用了自己的。 I don't know how your Set() method works; 我不知道您的Set()方法如何工作; this may take a little adaptation on your part. 您可能需要一点适应性。 That'll have to be your job; 那一定是你的工作; it's your turn. 轮到你了。 I wrote this because explaining the logic to you would take longer than writing the code. 我写这篇文章是因为向您解释逻辑要比编写代码花费更多的时间。 You should read this code and understand it, rather than simply pasting it into your project. 您应该阅读并理解该代码,而不是简单地将其粘贴到您的项目中。

Note that I've written this using conventional C# naming conventions. 请注意,我已经使用常规的C#命名约定编写了此代码。 The boolean properties no longer have the b prefix. 布尔属性不再具有b前缀。 This means you have to remove that prefix from the paths in the bindings in your XAML. 这意味着您必须从XAML绑定中的路径中删除该前缀。

Note also that I renamed Rights_All to All , and moved it to a different viewmodel . 还要注意,我将Rights_AllRights_AllAll并将其移至其他视图模型 It is now a member of the Rights viewmodel. 现在它是Rights视图模型的成员。 This also will require a change to your bindings. 这也将需要更改绑定。

You should consider using a Flags enum for your rights. 您应该考虑将Flags枚举用于您的权利。 This would simplify the code a bit, and make it easier to add additional rights in the future. 这样可以简化代码,并在将来增加附加权限。

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

Here is the answer to my solution (after getting suggestion from @Ed Plunkett and @zaitsman) I implemented INotifyProperty (by using MVVM Light way) to one of the classes in my Model. 这是我的解决方案的答案(在收到@Ed Plunkett和@zaitsman的建议后),我对Model中的一个类实现了INotifyProperty(通过使用MVVM Light方法)。

For my Model Class. 对于我的模型课。

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

For my VM. 对于我的VM。

    private Rights user_Rights;
    public Rights User_Rights
    {
        get { return user_Rights; }
        set { Set(ref user_Rights, value); }
    }

And for my View (XAML). 对于我的视图(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}" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM