0
votes

I am facing a problem in getting the value from VM for checkbox IsChecked binding value. (I'm using MVVM Light).

My issue: When checkbox IsChecked is changed, it is not firing back to my VM property that I bind to.

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).

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).

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.

<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. enter image description here

Any suggestion on where did I do wrong? Thanks.

2
Shouldn't your model (Rights) also implement INotifyPropertyChanged?zaitsman
I’m guessing that “not firing back to a vm property” is your way of saying that it’s not setting the properties of the Rights object. Is that what you’re trying to say? How are you checking that?15ee8f99-57ff-4f92-890c-b56153
Tested. Works as expected. Either your private meaning of "trigger back to VM" and "firing back to VM" is so exotic as to be unguessable with any confidence from the evidence in your question (are you hoping that default setters on Rights properties will somehow call the setter of User_Rights on a completely different class?), or you're looking at the wrong instance of Rights. If it's option #1, clarify. If it's option #2, just implement INotifyPropertyChanged on Rights. If it's #3, the question should be closed.15ee8f99-57ff-4f92-890c-b56153
Ideally, you should not reassign value of User_Rights again and again. Instead have a method inside Rights like SelectAll and UnselectAll and call from Rights_All.Nikhil Agrawal
@scsfdev “Fire” doesn’t mean that. I told you that several times. You should apologize for being deliberately difficult.15ee8f99-57ff-4f92-890c-b56153

2 Answers

0
votes

I don't know what your viewmodel base class is called, so I just used my own. I don't know how your Set() method works; 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. The boolean properties no longer have the b prefix. This means you have to remove that prefix from the paths in the bindings in your XAML.

Note also that I renamed Rights_All to All, and moved it to a different viewmodel. It is now a member of the Rights viewmodel. This also will require a change to your bindings.

You should consider using a Flags enum for your rights. 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;
                }
            }
        }
    }
}
0
votes

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.

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.

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

And for my View (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}" />