RaisePropertyChanged 不通知 parent

RaisePropertyChanged does not notify parent

我们有一个 parent class,其中有 children 的集合。两个 classes 都支持使用 Template10 的更改通知。更改通知在每个 class 中起作用(即当我们在同一个 class 中更新 属性 时)如下所示,但我们无法从 parent 触发更改通知child.

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

我们发现我们可以在 ParentViewModel 中使用 RaisePropertyChanged 来触发

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

Tax { get { return Total - Net; } }

ChildViewModel 我们有 ChildString。我们想通知 ParentStringChildString 的更改。

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 没有更新。我们如何在 ChildString 更新时强制 ParentString 更新?

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

nameof 运算符不能 "change" 事件源。您需要一种以某种方式触发 parent PropertyChanged 的方法。最简单的方法是在 ParentViewModel:

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

并从 child:

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

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

但是如果改变 ParentString 是带来这种依赖的唯一原因,那么从 child 中扔掉 parent 会很好。

由于 MyChildren 是一个可观察的集合,您可以订阅它的 CollectionChanged 事件。添加新 child 时,您可以订阅其 PropertyChanged,并观察 ChildString 变化以引发适当的 parent 事件。

是这样的:

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