如果在Windows 8.1应用程序中更新其中一个子项中的值,如何更新父ViewModel中的值

时间:2014-12-08 03:15:10

标签: c# wpf xaml mvvm windows-8.1

我有一个Windows 8.1应用程序,其父视图和子视图模型具有以下关系

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

在XAML中有TextBlock绑定到&#34; ParentAmount&#34;然后有一个ListView绑定到Observable集合&#34; Children&#34;。 ListView的Itemtemplate是一个带有TextBox的datatemplate,它与&#34; ChildAmount&#34;有双向绑定。用户可以修改子TextBox中的值

现在我的要求是当用户修改其中一个子金额时,使用其所有子金额的总和更新ParentAmount。我如何实现这一目标?

为了便于说明,我简化了上面粘贴的代码示例,ChildViewModel具有比可以看到的功能更多的功能,因此我不能用例如Double的List替换ChildViewModel的ObservableCollection。

如果有人能指出我正确的方向,我会很高兴。在此先感谢。

2 个答案:

答案 0 :(得分:3)

只需要很少的添加,就可以了。 具体的更改是为ObservableCollection中的每个子对象添加属性更改处理程序。

请注意,这是一个粗略的例子,让你走上正确的轨道 - 我没有解开事件处理程序,我重新计算了来自孩子的任何变化的父母金额(即我没有检查它是否是更改了ChildAmount,这意味着您最终会采取比必要更多的操作。我还没有放入任何代码来处理对ObservableCollection内容的更改,所以如果添加新项目,它们就不会附加属性更改事件处理程序 - 这对你来说很简单。

请注意我使用BaseViewModel - 这只是一个很好的做法,它可以避免在每个需要它的类上重新实现INotifyPropertyChanged接口。

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

答案 1 :(得分:2)

更优雅的方法是使用Reactive Extensions

首先你需要抓住

  

RX-主

来自程序包管理器控制台

然后,创建一个static class来托管使用Rx实现的扩展方法。像这样的东西 -

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

最后,您可以在ParentViewModel构造函数(或任何必要的位置)中调用此方法。

    // 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");
        });