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
。我们想通知 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
没有更新。我们如何在 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));
}
}
}
我们有一个 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
。我们想通知 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
没有更新。我们如何在 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));
}
}
}