0

I have fiddled around with MVVM lately in C# and i got to the point where i thought i understood how bindings work but then this happened...

using System;
using System.Collections.Generic;
using System.Text;

namespace API
{
    public class ApiViewModel : BaseViewModel
    {
        public bool CustomerIsChecked { get; set; }

        public bool StorageIsChecked { get; set; }

        public bool ArticlesIsChecked { get; set; }


        public bool Transfer()
        {
            if(CustomerIsChecked == true)
            {
                return true; 
            }
            return false;
        }
        public override string ToString()
        {
            return Transfer().ToString(); 
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using PropertyChanged; 

namespace API
{
    [AddINotifyPropertyChangedInterface]
    public class BaseViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };

    }
}

This works if i just like send in a string or anything to the binding directly but when i try to send in the value of transfer it does not work it gives me an empty button why is this? My question is why this doesnt work quz basicly when you are using a string without any parameters or anything and just do a getter or setter it works but to send in a string that has this doesnt? Why is this?

  • 1
    You should implement `INotifyPropertyChanged` interface for that [Implementing INotifyPropertyChanged - does a better way exist?](https://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist) – Pavel Anikhouski Jan 17 '20 at 19:42
  • what does your BaseViewModel look like? I don't see where you are invoking the `INotifyPropertyChanged` event... – Trae Moore Jan 17 '20 at 19:43
  • have added BAseViewmodel –  Jan 17 '20 at 19:45

1 Answers1

0

You should remove the () behind the Transfer method:

public class ApiViewModel : BaseViewModel
{
    public bool CustomerIsChecked { get; set; }

    public bool StorageIsChecked { get; set; }

    public bool ArticlesIsChecked { get; set; }


    public bool Transfer  // <- remove ()
    {
        get   // it should have a getter.
        {
            if(CustomerIsChecked == true)
            {
                return true; 
            }
            return false;
        }
    }
    public override string ToString()
    {
        return Transfer().ToString(); 
    }
}

The code of Transfer could be simplified. It should return true when CustomerIsChecked is true, otherwise false.

So:

public bool Transfer
{
    get => CustomerIsChecked;
}

My old answer (I didn't understood the question)

You should implement the INotifyPropertyChanged and raise he event. Too bad you need to have a full property (add a field)

Since you can only invoke an event from the class it self, you need to implement a method to raise the event in the base class.

For example:

public class BaseViewModel : INotifyPropertyChanged
{
    protected void RaisePropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    public event PropertyChangedEventHandler PropertyChanged;

}

public class ApiViewModel : BaseViewModel
{
    private bool _customerIsChecked;

    public bool CustomerIsChecked
    {
        get { return _customerIsChecked; }
        set
        {
            _customerIsChecked = value;
            RaisePropertyChanged(nameof(CustomerIsChecked));
        }
    }
}

It's also possible to create a helper method which takes care of the property changed.

I like this style which allows the new expression-bodied member,

public class BaseViewModel : INotifyPropertyChanged
{
    public bool SetField<T>(ref T field, T value, [CallerMemberName] string memberName = "")
    {
        if (field != null)
        {
            if (field.Equals(value))
                return false;
        }
        else if (value != null)
            return false;

        field = value;
        RaisePropertyChanged(memberName);
        return true;
    }

    protected void RaisePropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    public event PropertyChangedEventHandler PropertyChanged;

}

public class ApiViewModel : BaseViewModel
{
    private bool _customerIsChecked;

    public bool CustomerIsChecked
    {
        get => _customerIsChecked;
        set => SetField(ref _customerIsChecked, value);
    }
}
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
  • My question has nothing to do with getting the value from CustomerIsChecked im trying to get the value from Transfer onto a button when CustomerIsChecked changes???? –  Jan 17 '20 at 20:00
  • the transfer string is not filled yet quz i am in testing not release –  Jan 17 '20 at 20:01
  • @jens my excuus I don't understand your question then. _"but when i try to send in the value of transfer it does not work it gives me an empty button why is this?"_ Transfer is not a value?? it's a method... – Jeroen van Langen Jan 17 '20 at 20:06
  • yes transfer is a public string that returns true if CustomerIsChecked == true but then if you bind it to the method it does not worki do not get true or false in the button i get an empty button –  Jan 17 '20 at 20:10
  • Do i have to create a string that has a getter and setter and that is set to the value that returns from Transfer then? –  Jan 17 '20 at 20:12
  • No, `public bool Transfer()` <- is a method and cannot be bound with binding. You should make it a property instead. I'll add it to my answer – Jeroen van Langen Jan 17 '20 at 20:13
  • @jens yes, it should be a property. – Jeroen van Langen Jan 17 '20 at 20:15
  • this is what i asked in one of my comments but okey well wouldn't it be a bad interaction if you later on add like if(CustomerIsChecked){saveCustomer() return true;} –  Jan 17 '20 at 20:17