C# 轻松地将通知传播到WPF中的UI
因此,我看到了一些对类似问题的回答,但我想知道我所想到的某种范式在C#中是否可行。首先,我将阐述这个问题: 我有一个用C#开发的MVVM应用程序。模型的特性会发生更改,当模型中的单个特性发生更改时,它通常会影响视图模型中的多个特性。因此,视图模型将侦听模型上的更改。视图将侦听视图模型上的更改 在我的视图模型中,我最终得到如下代码:C# 轻松地将通知传播到WPF中的UI,c#,wpf,mvvm,attributes,inotifypropertychanged,C#,Wpf,Mvvm,Attributes,Inotifypropertychanged,因此,我看到了一些对类似问题的回答,但我想知道我所想到的某种范式在C#中是否可行。首先,我将阐述这个问题: 我有一个用C#开发的MVVM应用程序。模型的特性会发生更改,当模型中的单个特性发生更改时,它通常会影响视图模型中的多个特性。因此,视图模型将侦听模型上的更改。视图将侦听视图模型上的更改 在我的视图模型中,我最终得到如下代码: private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyCh
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
string prop_name = e.PropertyName;
if (prop_name.Equals("some_property_on_the_model"))
{
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
}
else if (...)
{
... etc ...
}
}
[ListenToModelProperty("some_property_on_the_model")]
[OnPropertyChanged("MyButtonVisibility")]
public Visibility MyButtonVisibility
{
get
{
if (model.some_property_on_the_model == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
prop_name = e.PropertyName;
foreach (var property in view_model)
{
var attributes = property.GetCustomAttributes(typeof(ListenToModelPropertyAttribute));
var descriptions = attributes.Select(x => x.Description);
if (descriptions.Contains(prop_name))
{
notification_to_make = property.GetCustomAttributes(typeof(OnPropertyChangedAttribute));
string notification_string = notification_to_make[0].Description;
NotifyPropertyChanged(notification_string);
}
}
}
using System;
using System.Collections.Generic;
namespace TestPropagationOfPropertyChanges
{
[AttributeUsage(AttributeTargets.All)]
public class ListenForModelPropertyChangedAttribute : System.Attribute
{
public List<string> ModelPropertyNames = new List<string>();
public ListenForModelPropertyChangedAttribute (string [] propertyNames)
{
ModelPropertyNames.AddRange (propertyNames);
}
}
}
这很烦人,因为它看起来很凌乱。如果在视图模型中添加新属性后忘记编辑此函数,则很容易导致错误
这就是我想做的,但我不知道这是否可行。所以我希望你们中的一位能帮助我理解这是否可能
如果我能使用C#的“属性”特性来处理属性更改传播,那将非常酷
所以可能是这样的:
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
string prop_name = e.PropertyName;
if (prop_name.Equals("some_property_on_the_model"))
{
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
}
else if (...)
{
... etc ...
}
}
[ListenToModelProperty("some_property_on_the_model")]
[OnPropertyChanged("MyButtonVisibility")]
public Visibility MyButtonVisibility
{
get
{
if (model.some_property_on_the_model == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
prop_name = e.PropertyName;
foreach (var property in view_model)
{
var attributes = property.GetCustomAttributes(typeof(ListenToModelPropertyAttribute));
var descriptions = attributes.Select(x => x.Description);
if (descriptions.Contains(prop_name))
{
notification_to_make = property.GetCustomAttributes(typeof(OnPropertyChangedAttribute));
string notification_string = notification_to_make[0].Description;
NotifyPropertyChanged(notification_string);
}
}
}
using System;
using System.Collections.Generic;
namespace TestPropagationOfPropertyChanges
{
[AttributeUsage(AttributeTargets.All)]
public class ListenForModelPropertyChangedAttribute : System.Attribute
{
public List<string> ModelPropertyNames = new List<string>();
public ListenForModelPropertyChangedAttribute (string [] propertyNames)
{
ModelPropertyNames.AddRange (propertyNames);
}
}
}
请注意,上面的代码并不是真正的代码。它肯定不会编译,也不会工作。但是我想看看在C#中是否可以实现上述功能。是否可以使用属性执行类似的操作?或者有没有一个库可以让这样的事情成为可能?我已经想出了如何做到这一点!这相当简单。我将在这里发布相关代码,感兴趣的人可以在我刚刚制作的github存储库中找到所有代码: 首先,我创建了一个自定义属性类。它是一个简单的类,将字符串数组作为其构造函数的参数。这允许您侦听模型上的多个属性以进行更改。看起来是这样的:
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
string prop_name = e.PropertyName;
if (prop_name.Equals("some_property_on_the_model"))
{
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
NotifyPropertyChanged("some_property_on_the_view_model");
}
else if (...)
{
... etc ...
}
}
[ListenToModelProperty("some_property_on_the_model")]
[OnPropertyChanged("MyButtonVisibility")]
public Visibility MyButtonVisibility
{
get
{
if (model.some_property_on_the_model == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
prop_name = e.PropertyName;
foreach (var property in view_model)
{
var attributes = property.GetCustomAttributes(typeof(ListenToModelPropertyAttribute));
var descriptions = attributes.Select(x => x.Description);
if (descriptions.Contains(prop_name))
{
notification_to_make = property.GetCustomAttributes(typeof(OnPropertyChangedAttribute));
string notification_string = notification_to_make[0].Description;
NotifyPropertyChanged(notification_string);
}
}
}
using System;
using System.Collections.Generic;
namespace TestPropagationOfPropertyChanges
{
[AttributeUsage(AttributeTargets.All)]
public class ListenForModelPropertyChangedAttribute : System.Attribute
{
public List<string> ModelPropertyNames = new List<string>();
public ListenForModelPropertyChangedAttribute (string [] propertyNames)
{
ModelPropertyNames.AddRange (propertyNames);
}
}
}
在本例中,视图模型具有“全名”属性。因此,它希望听到模型上的名字或姓氏发生的任何更改,然后对其中任何一个的更改做出反应。我意识到这不是使用这种系统的最佳“现实世界”场景,但它确实有助于说明这一概念。我的视图模型的第一部分如下:
using System;
namespace TestPropagationOfPropertyChanges
{
public class ViewModel : NotifyPropertyChangedObject
{
#region Private data members
//This is public for testing purposes
public Model _model = new Model();
#endregion
#region Constructors
public ViewModel ()
{
_model.PropertyChanged += ReactToModelPropertyChanged;
}
#endregion
#region Properties
[ListenForModelPropertyChangedAttribute(new string [] {"FirstName", "LastName"})]
public string FullName
{
get
{
return _model.FirstName + _model.LastName;
}
}
最后,视图模型以对模型上的更改作出反应的方法结束。通常,在大型复杂应用程序中,此方法可能包含一个大型if-else语句,其中包含大量对NotifyPropertyChanged的调用。相反,我们现在只需遍历视图模型的属性,看看哪些属性订阅了已更改的模型属性。见下文:
void ReactToModelPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//Get the name of the property that was changed on the model
string model_property_changed = e.PropertyName;
//Get a System.Type object representing the current view-model object
System.Type t = typeof(ViewModel);
//Retrieve all property info for the view-model
var property_info = t.GetProperties();
//Iterate through each property
foreach (var property in property_info)
{
//Get the custom attributes defined for this property
var attributes = property.GetCustomAttributes (false);
foreach (var attribute in attributes)
{
//If the property is listening for changes on the model
var a = attribute as ListenForModelPropertyChangedAttribute;
if (a != null)
{
//If the property that was changed on the model matches the name
//that this view-model property is listening for...
if (a.ModelPropertyNames.Contains(model_property_changed))
{
//Notify the UI that the view-model property has been changed
NotifyPropertyChanged (property.Name);
}
}
}
}
}
总的来说,它工作得非常出色,这正是我所需要的。对于感兴趣的人来说,此代码可以很容易地扩展,使其功能更加强大。这也是我们团队经常头疼的问题。Fody PropertyChanged试图以稍微不同的方式帮助解决此问题。我个人还没有在生产中尝试过!