0

I have model and viewmodel in my WPF app simple as shown below.

My intention is to update HumanizedPrice property with some string from WCF when GivenPrice is changed. HumanizedPrice is based on GivenPrice and WCF is needed to get it. What is the best MVVM-compatibile approach for this?

Model:

class Price : INotifyPropertyChanged
{
    public string GivenPrice
    {
        get
        {
            return _givenPrice;
        }

        set
        {
            if (_givenPrice != value)
            {
                _givenPrice = value;
                RaisePropertyChanged("GivenPrice");
                RaisePropertyChanged("HumanizedPrice");
            }
        }
    }

    public string HumanizedPrice
    {
        get
        {
            return _humanizedPrice;
        }

        set
        {
            if (_humanizedPrice != value)
            {
                _humanizedPrice = value;
                RaisePropertyChanged("HumanizedPrice");
            }
        }
    }

    private string _givenPrice;
    private string _humanizedPrice;

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));            
    }
}

ViewModel:

class PriceViewModel
{

    public PriceViewModel()
    {
        LoadPrices();
    }

    public ObservableCollection<Price> Prices
    {
        get;
        set;
    }

    public void LoadPrices()
    {
        ObservableCollection<Price> prices = new ObservableCollection<Price>();

        prices.Add(new Price { GivenPrice = "221 331,44" });
        prices.Add(new Price { GivenPrice = "2 331,44" });
        prices.Add(new Price { GivenPrice = "331,44" });
        prices.Add(new Price { GivenPrice = "0,44" });

        Prices = prices;

    }
}
  • Where/how does WCF come into this? – Herohtar Jan 13 '20 at 05:17
  • A few comments to help you may be. 1 - Why your Model is INotifyPropertyChanged, it supposed to be ViewModel. 2 - Once you move that notification thing to ViewModel (where the WCF call would be too) - you know when to update HumanizedPrice. – Prateek Shrivastava Jan 13 '20 at 05:30
  • 1
    I think that is the most common approach to have MVVM in WPF: https://www.tutorialspoint.com/mvvm/mvvm_first_application.htm – Sebastian Xawery Wiśniowiecki Jan 13 '20 at 05:37
  • If you make the Model Notifiable - then only the Model knows when GivenPrice changed and then you will have to Inject WCF call into the Model. Do you get the problem here? The moment you make Model as Notifiable you are wiring it to do more than just hold State. Keep Model as a plain class. Keep all transient states in View Model (Notifiable). – Prateek Shrivastava Jan 13 '20 at 05:46
  • 1
    @PrateekShrivastava I have to disagree. It's a very popular approach. Even Brian Lagunas suggests that it's up to Model to implement INotifyPropertyChanged. And there's a way to hanlde the WCF call in VM using that approach. I'll post it as an answer. – Gleb Jan 13 '20 at 05:46
  • If you were to have a Command on your VM, then you could put the call to your WCF in the command, otherwise I can only think of the property setter of Given price to call the WCF service and then change the Humanized Price. How do you present this to the user? FYI, There is nothing wrong with having Model implementing INPC, how would UI know if HumanizedPrice has changed? – XAMlMAX Jan 13 '20 at 10:32
  • This model is just model of ObservableCollection that's why it implements INotifyProperty - list will be also editable after creating... It will be list of editable textboxes that even after first translation by WCF will be albe to translate again by editing GivenPrice from the list – Sebastian Xawery Wiśniowiecki Apr 10 '20 at 22:16

1 Answers1

1

Here's what I can suggest:

public void LoadPrices()
{
    // Prices loading...

    Prices = prices;

    foreach (var price in Prices)
    {
        price.PropertyChanged += (s, e) => 
        {
            if (e.PropertyName.Equals(nameof(Price.GivenPrice)))
            {
                // do your WCF call here...
            }
        };
    }
}

Note! If you're going to add / remove prices you should also subscribe on CollectionChanged of ObservableCollection and handle subscriptions manually:

Prices.CollectionChanged += (s, e) => 
{
    // Subscribing on property changed event for newly added prices
    if (e.Action == NotifyCollectionChangedAction.Add)
        foreach (Price item in e.NewItems)
            item.PropertyChanged += WCFCallHandler;
    // Unsubscribing from property changed event of removed prices 
    if (e.Action == NotifyCollectionChangedAction.Remove)
        foreach (Price item in e.OldItems)
            item.PropertyChanged -= WCFCallHandler;
};
Gleb
  • 1,723
  • 1
  • 11
  • 24
  • Thanks. It looks like perfect solution. Now I am looking for solution that let me assign delegate with WCF call from the parent window which contains referenece to WCF service https://stackoverflow.com/questions/61149278/wpf-assign-delegate-to-usercontrol-from-parent-window – Sebastian Xawery Wiśniowiecki Apr 10 '20 at 22:12