在wpf应用程序的视图模型中,我经常需要声明如下属性:
public string IdAnalisi5
{
get { return ricettaCorrente.IdAnalisi1; }
set
{
ricettaCorrente.IdAnalisi5 = value;
OnPropertyChanged(nameof(IdAnalisi5));
}
}
该类实现OnPropertyChanged方法来触发ui的更新,但是大多数时候我只需要调用此方法,并且是很多重复的代码。
实际上可以创建一个属性,我可以将其添加到所有类中,并使用在设置值后调用该方法的方法来实现一个类或接口吗?
我想转换成这样的东西
[PropertyChanged(nameof(IdAnalisi5)]
public string IdAnalisi5 => ricettaCorrente.IdAnalisi1;
通常可以节省很多代码。
答案 0 :(得分:1)
正如我所说,我不知道通过“属性”解决此问题的方法,但是有一些动态代理模式的实现可简化OnPropertyChanged
的使用。
创建代理
public class ProxyCreator
{
public static T MakeINotifyPropertyChanged<T>() where T : class, new ()
{
//Creates a proxy generator
ProxyGenerator proxyGen = new ProxyGenerator();
//Generates a proxy using our Interceptor and implementing INotifyPropertyChanged
var proxy = proxyGen.CreateClassProxy(
typeof (T),
new Type[] { typeof (INotifyPropertyChanged) },
ProxyGenerationOptions.Default,
new NotifierInterceptor()
);
return proxy as T;
}
}
拦截器,它主要做两件事:
它公开了PropertyChangedEventHandler
,
当使用好名字调用设置器时,它将引发PropertyChangedEventHandler
事件。此外,它还缓存了PropertyChangedEventArgs
,以提高性能。
public class NotifierInterceptor : IInterceptor
{
private PropertyChangedEventHandler handler;
public static Dictionary<String, PropertyChangedEventArgs> _cache =
new Dictionary<string, PropertyChangedEventArgs>();
public void Intercept(IInvocation invocation)
{
//Each subscription to the PropertyChangedEventHandler is intercepted (add)
if (invocation.Method.Name == "add_PropertyChanged")
{
handler = (PropertyChangedEventHandler)
Delegate.Combine(handler, (Delegate)invocation.Arguments[0]);
invocation.ReturnValue = handler;
}
//Each de-subscription to the PropertyChangedEventHandler is intercepted (remove)
else if (invocation.Method.Name == "remove_PropertyChanged")
{
handler = (PropertyChangedEventHandler)
Delegate.Remove(handler, (Delegate)invocation.Arguments[0]);
invocation.ReturnValue = handler;
}
//Each setter raise a PropertyChanged event
else if (invocation.Method.Name.StartsWith("set_"))
{
//Do the setter execution
invocation.Proceed();
//Launch the event after the execution
if (handler != null)
{
PropertyChangedEventArgs arg =
retrievePropertyChangedArg(invocation.Method.Name);
handler(invocation.Proxy, arg);
}
}
else invocation.Proceed();
}
// Caches the PropertyChangedEventArgs
private PropertyChangedEventArgs retrievePropertyChangedArg(String methodName)
{
PropertyChangedEventArgs arg = null;
NotifierInterceptor._cache.TryGetValue(methodName, out arg);
if (arg == null)
{
arg = new PropertyChangedEventArgs(methodName.Substring(4));
NotifierInterceptor._cache.Add(methodName, arg);
}
return arg;
}
}
最后的用法是这样的:
MyBusinessObject myBusinessObject;
DataContext = myBusinessObject = ProxyCreator.MakeINotifyPropertyChanged<MyBusinessObject>();
我还发现了动态代理的其他实现方式也是如此:
Implement InotifyPropertyChanged with Castle.DynamicProxy
希望对您有所帮助:)
答案 1 :(得分:0)
您可以使用MVVM Light Toolkit。您需要从ViewModelBase
继承视图模型,然后才能编写如下代码:
public string IdAnalisi5
{
get => ricettaCorrente.IdAnalisi5;
set => Set(ref ricettaCorrente.IdAnalisi5, value);
}
请注意,这仅在ricettaCorrente.IdAnalysi5
是字段而非属性的情况下有效。
MVVM Light Toolkit不是唯一提供此功能的工具。其他类似工具包括Prism和Caliburn.Micro。