How to update a value in parent ViewModel if value in one of it's child is updated in windows 8.1 app

拟墨画扇 提交于 2020-01-04 04:24:05

问题


I have a Windows 8.1 application with a parent and child viewmodel in the following relationship

ParentViewModel

class ParentViewModel {
    private double _parentAmount;
    public double parentAmount
    {
        get { return _parentAmount; }
        set
        {
            if (value != _parentAmount)
            {
                _parentAmount = value;
                NotifyPropertyChanged("parentAmount");
            }
        }
    }

    private ObservableCollection<ChildViewModel> _children;
    public ObservableCollection<ChildViewModel> children
    {
        get { return _children; }
        set
        {
            if (value != _children)
            {
                _children = value;
                NotifyPropertyChanged("children");
            }
        }
    }
}

ChildViewModel

class ChildViewModel {
    private double _ChildAmount;
    public double ChildAmount
    {
        get { return _ChildAmount; }
        set
        {
            if (value != _ChildAmount)
            {
                _ChildAmount = value;
                NotifyPropertyChanged("ChildAmount");
            }
        }
    }
}

In the XAML there is TextBlock that is bound to the "ParentAmount" and then there is a ListView bound to the Observable collection "Children". ListView's Itemtemplate is a datatemplate with a TextBox with a two way bind to the "ChildAmount". The user can modify the value in the child TextBox

Now my requriement is to update the ParentAmount with the sum of all its child amount on the fly when the user modifies one of the child amounts. How do I achieve this?

For illustration purpose I have simplified the code example pasted above, the ChildViewModel has more functionality than what can be seen hence I can't replace that ObservableCollection of ChildViewModel with a List of double for instance.

I would be very glad if someone can point me in the right direction. Thanks in Advance.


回答1:


With a very small addition, this will do the trick. The specific changes are adding a property change handler for each child object in the ObservableCollection.

Note that this is a crude example to set you on the right track - I haven't unhooked the event handlers, and I recalculate the parent amount on any change from the child (i.e. I don't check that it was the ChildAmount that changed, this means you end up with more action than is necessary). I also haven't put in any code to handle changes to the contents of the ObservableCollection so if new items are added to it they won't have a property change event handler attached - this is simple for you to do yourself.

Note my use of a BaseViewModel - this is just good practice, it saves you from reimplementing the INotifyPropertyChanged interface on every class that needs it.

class ParentViewModel : BaseViewModel
{
    private double _parentAmount;
    public double parentAmount
    {
        get { return _parentAmount; }
        set
        {
            if (value != _parentAmount)
            {
                _parentAmount = value;
                NotifyPropertyChanged("parentAmount");
            }
        }
    }

    private ObservableCollection<ChildViewModel> _children;
    public ObservableCollection<ChildViewModel> children
    {
        get { return _children; }
        set
        {
            if (value != _children)
            {
                _children = value;
                foreach (var child in _children)
                    child.PropertyChanged += ChildOnPropertyChanged;
                NotifyPropertyChanged("children");
            }
        }
    }

    private void ChildOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        parentAmount = children.Sum(p => p.ChildAmount);
    }
}

class ChildViewModel : BaseViewModel
{
    private double _ChildAmount;
    public double ChildAmount
    {
        get { return _ChildAmount; }
        set
        {
            if (value != _ChildAmount)
            {
                _ChildAmount = value;
                NotifyPropertyChanged("ChildAmount");
            }
        }
    }
}


public class BaseViewModel : INotifyPropertyChanged
{
    protected void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}



回答2:


A more elegant way is to use Reactive Extensions.

First you need to grab

Rx-Main

from Package Manager Console.

Then, create a static class to host your extension method implemented using Rx. Something like this -

public static class Extensions
{
    public static IObservable<T> OnPropertyChanges<T>(this T source, string propertyName)
        where T : INotifyPropertyChanged
    {
        return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                handler => handler.Invoke,
                h => source.PropertyChanged += h,
                h => source.PropertyChanged -= h)
                .Where(p => p.EventArgs.PropertyName == propertyName)
                .Select(_ => source);
    }
}

Lastly, you call this method in your ParentViewModel's constructor (or anywhere necessary).

    // whenever the ChildAmount property of any ChildViewModel has changed, do something
    Observable.Merge(children.Select(c => c.OnPropertyChanges("ChildAmount")))
        .Subscribe((c) =>
        {
            // update your parent amount here
            NotifyPropertyChanged("parentAmount");
        });


来源:https://stackoverflow.com/questions/27350868/how-to-update-a-value-in-parent-viewmodel-if-value-in-one-of-its-child-is-updat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!