如果 viewmodel1 属性 发生变化,通知 viewmodel2
notify viewmodel2 if viewmodel1 property changes
我在 wpf +mvvm 中有一个场景,即如果我在 viewmodel1 中的特定 属性 发生变化,那么我想通知具有可观察集合的 viewmodel2 属性 "A" 已经改变
1) 我想为特定 属性 而非所有人开火。
我试过下面的代码但没有用。请告诉我我是怎么做到的。
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Create custom event
public event EventHandler NotifyChange;
private string testProperty;
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
}
}
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
// Fire your custom event if a property changed
NotifyChange(this, null);
}
}
}
public class Model2 : INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public Model2()
{
// Assuming there is an accessible instance of model1
Model1 m1Instance = new Model1();
// Hook up your NotifyChange event from model1
m1Instance.NotifyChange += Model1Changed;
}
private void Model1Changed(object sender, EventArgs e)
{
// this will be triggered on change in model1
}
private void OnCollectionChanged(object singleObject)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, singleObject));
}
}
那是因为您没有注册 PropertyChanged
。您正在 NotifyChange
上注册您的事件处理程序,以便 Model1
中的 PropertyChanged
是 NULL
,因此不会触发 NotifyChange
。
因此,您需要按以下方式实现 OnPropertyChanged
:
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
if (NotifyChange != null)
NotifyChange(this, null);
}
最后,如果您希望针对特定 属性 触发您的 NotifyChange
,请调整上面的代码以在触发事件之前检查 propName
。
如果这只是为了通知 Model2,我认为您不需要所有这些实现。你可以这样做
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
//Here you can call a method of Model2 sating that its changed
Model2 m2Instance = new Model2();
m2Instance.ValueChanged();
}
}
在模型 2 中添加方法 ValueChanged。
使用 PubSub 事件
我的建议是调查 PubSub
个事件。
我的建议是使用 Prism。这里有更多信息:http://www.c-sharpcorner.com/UploadFile/5ffb84/prism-event-aggregator-in-wpf-with-mvvm/
在这种情况下,您将坚持正确的 MVVM 实践。
这是 MSDN 的有用指南:https://msdn.microsoft.com/en-us/library/ff649664.aspx
仔细阅读它的工作原理,以及如何 use/implement 它。
或者
这会起作用,但如果可能,我仍然会推迟使用 PubSub 事件。
你可以试试这个:
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _property;
public string Property
{
get { return _property; }
set
{
_property = value;
OnPropertyChanged("Property");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Model2
{
public Model2()
{
// You might be storing your Model1 as a property in the Model2?
// I don't know, but I've put it in the constructor just for example.
var model1 = new Model1();
model1.PropertyChanged += OnModel1PropertyChanged;
}
private void OnModel1PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Property")
{
// Do stuff here when the right property has changed in model 1
}
}
}
我仅在 Model2
的构造函数中 new
建立了一个 Model1
作为示例 - 您可能正在分配它并将其存储为字段或 属性 Model2
ViewModel 中的其他地方。
如果您在 ViewModel 中有 ViewModel(父 VM > 子 VM),这可能特别有用。
我经常使用父 > 子 VM,我不认为它违反 MVVM 最佳实践,但我仍然 使用 EventAggregator
,而不是 event
s.
附带说明一下,如果您使用的是 C#6:
- 使用
nameof(Property)
代替"magic strings"(例如"Property"
)。这使得重构变得更加容易,并且编译器可以告诉您有关错误的信息——但本质上是做同样的工作。在 set
ter 的 OnPropertyChanged()
调用中使用它
- 检查属性名称时也可以使用
nameof
关键字,原理同上。像这样:if (e.PropertyName == nameof(Model1.Property)) ...
- 使用空传播:
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
。将 OnPropertyChanged
的方法体更改为一个漂亮的单行代码,同时仍然做同样的工作
我跑题了
我会 总是 考虑在可能的情况下坚持正确的 MVVM 实践。
我每天都使用 Prism 的 EventAggregator
,我会发誓。
仔细阅读 PubSub Events(您可以使用任何类型的事件聚合器,但我建议最好使用 Prism 的)
希望这对您有所帮助! :)
我在 wpf +mvvm 中有一个场景,即如果我在 viewmodel1 中的特定 属性 发生变化,那么我想通知具有可观察集合的 viewmodel2 属性 "A" 已经改变 1) 我想为特定 属性 而非所有人开火。
我试过下面的代码但没有用。请告诉我我是怎么做到的。
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Create custom event
public event EventHandler NotifyChange;
private string testProperty;
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
}
}
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
// Fire your custom event if a property changed
NotifyChange(this, null);
}
}
}
public class Model2 : INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public Model2()
{
// Assuming there is an accessible instance of model1
Model1 m1Instance = new Model1();
// Hook up your NotifyChange event from model1
m1Instance.NotifyChange += Model1Changed;
}
private void Model1Changed(object sender, EventArgs e)
{
// this will be triggered on change in model1
}
private void OnCollectionChanged(object singleObject)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, singleObject));
}
}
那是因为您没有注册 PropertyChanged
。您正在 NotifyChange
上注册您的事件处理程序,以便 Model1
中的 PropertyChanged
是 NULL
,因此不会触发 NotifyChange
。
因此,您需要按以下方式实现 OnPropertyChanged
:
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
if (NotifyChange != null)
NotifyChange(this, null);
}
最后,如果您希望针对特定 属性 触发您的 NotifyChange
,请调整上面的代码以在触发事件之前检查 propName
。
如果这只是为了通知 Model2,我认为您不需要所有这些实现。你可以这样做
public string TestProperty
{
get
{
return testProperty;
}
set
{
testProperty = value;
// If changing properties, fire your OnPropertyChanged to update UI
OnPropertyChanged("TestProperty");
//Here you can call a method of Model2 sating that its changed
Model2 m2Instance = new Model2();
m2Instance.ValueChanged();
}
}
在模型 2 中添加方法 ValueChanged。
使用 PubSub 事件
我的建议是调查 PubSub
个事件。
我的建议是使用 Prism。这里有更多信息:http://www.c-sharpcorner.com/UploadFile/5ffb84/prism-event-aggregator-in-wpf-with-mvvm/
在这种情况下,您将坚持正确的 MVVM 实践。
这是 MSDN 的有用指南:https://msdn.microsoft.com/en-us/library/ff649664.aspx
仔细阅读它的工作原理,以及如何 use/implement 它。
或者
这会起作用,但如果可能,我仍然会推迟使用 PubSub 事件。
你可以试试这个:
public class Model1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _property;
public string Property
{
get { return _property; }
set
{
_property = value;
OnPropertyChanged("Property");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Model2
{
public Model2()
{
// You might be storing your Model1 as a property in the Model2?
// I don't know, but I've put it in the constructor just for example.
var model1 = new Model1();
model1.PropertyChanged += OnModel1PropertyChanged;
}
private void OnModel1PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Property")
{
// Do stuff here when the right property has changed in model 1
}
}
}
我仅在 Model2
的构造函数中 new
建立了一个 Model1
作为示例 - 您可能正在分配它并将其存储为字段或 属性 Model2
ViewModel 中的其他地方。
如果您在 ViewModel 中有 ViewModel(父 VM > 子 VM),这可能特别有用。
我经常使用父 > 子 VM,我不认为它违反 MVVM 最佳实践,但我仍然 使用 EventAggregator
,而不是 event
s.
附带说明一下,如果您使用的是 C#6:
- 使用
nameof(Property)
代替"magic strings"(例如"Property"
)。这使得重构变得更加容易,并且编译器可以告诉您有关错误的信息——但本质上是做同样的工作。在set
ter 的 - 检查属性名称时也可以使用
nameof
关键字,原理同上。像这样:if (e.PropertyName == nameof(Model1.Property)) ...
- 使用空传播:
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
。将OnPropertyChanged
的方法体更改为一个漂亮的单行代码,同时仍然做同样的工作
OnPropertyChanged()
调用中使用它
我跑题了
我会 总是 考虑在可能的情况下坚持正确的 MVVM 实践。
我每天都使用 Prism 的 EventAggregator
,我会发誓。
仔细阅读 PubSub Events(您可以使用任何类型的事件聚合器,但我建议最好使用 Prism 的)
希望这对您有所帮助! :)