RaisePropertyChanged不通知父级

时间:2017-03-06 06:22:07

标签: c# mvvm uwp template10

我们有一个父类,它有一个子集合。这两个类都支持使用Template10进行更改通知。更改通知在每个类中起作用(即当我们更新同一类中的属性时),如下所示,但是我们无法触发来自子项的父级的更改通知。

public class ParentViewModel : ViewModelBase
{
    public string ParentString { get }
    public decimal? Net { get { return Total / (1 + TaxRate / 100); } }        
    public decimal? Tax { get { return Total - Net; } }
    decimal? _Total = default(decimal?);
    public decimal? Total
    {
        get
        {
            return _Total;
        }
        set
        {
            Set(ref _Total, value);
            RaisePropertyChanged(nameof(Net));
            RaisePropertyChanged(nameof(Tax));
        }
    }

    public ObservableCollection<ChildViewModel> MyChildren { get; set; }

我们发现我们可以使用RaisePropertyChanged中的ParentViewModel来解雇

Net { get { return Total / (1 + TaxRate / 100); } }

Tax { get { return Total - Net; } }

ChildViewModel我们ChildString。我们希望将ParentString的更改通知ChildString

public class ChildViewModel : ViewModelBase
{
    ParentViewModel MyParent { get; set; }
    string _ChildString = default(string);
    public string ChildString
    {
        get
        {
            return _ChildString;
        }
        set
        {
            Set(ref _ChildString, value);
            RaisePropertyChanged(nameof(this.MyParent.ParentString));
        }
    }

但是ParentString没有更新。 ParentString更新时,我们如何强制ChildString更新?

1 个答案:

答案 0 :(得分:1)

无论nameof参数如何,当您调用ChildViewModel.RaisePropertyChanged时,都会在子视图模型上触发事件。

nameof运营商无法改变&#34;事件来源。你需要一种以某种方式解雇父PropertyChanged的方法。最简单的方法是在ParentViewModel

中制作适当的方法
public void RaiseParentStringChanged()
{
    RaisePropertyChanged(nameof(ParentString));
}

并从孩子那里打电话:

public string ChildString
{
    get
    {
        return _ChildString;
    }
    set
    {
        Set(ref _ChildString, value);

        // assuming, that parent is assigned at this point
        MyParent.RaiseParentStringChanged();
    }
}

但如果改变ParentString是导致这种依赖的唯一原因,那么将父母从孩子身上扔掉会很好。

由于MyChildren是一个可观察的集合,您可以订阅其CollectionChanged事件。添加新子项时,您可以在其PropertyChanged上进行订阅,并注意ChildString更改以提出相应的父级事件。

它是这样的:

// non-related code is omitted
public class ParentViewModel: ViewModelBase
{
    private ObservableCollection<ChildViewModel> children;

    public string ParentString { get; }

    // don't do collection properties on view models
    // as get-set ones, unless you know exactly what are you doing;
    // usually you don't need to set them explicitly from outside
    public ObservableCollection<ChildViewModel> MyChildren
    {
        get
        {
            if (children == null)
            {
                children = new ObservableCollection<ChildViewModel>();
                children.CollectionChanged += ChildrenChanged;
            }
            return children;
        }
    }

    private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // assuming, that only two actions ("add" and "remove") are available;
        // if you really need to nadle "reset" and "replace", add appropriate code;
        // note, that "reset" doesn't provide acceess to removed items
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                ((ChildViewModel)e.NewItems[0]).PropertyChanged += ChildPropertyChanged;
                break;
            case NotifyCollectionChangedAction.Remove:
                ((ChildViewModel)e.OldItems[0]).PropertyChanged -= ChildPropertyChanged;
                break;
        }
    }

    private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(ChildViewModel.ChildString))
        {
            RaisePropertyChanged(nameof(ParentString));
        }
    }
}