我最近开始在 Unity 应用程序块中使用拦截,并且在尝试获取嵌套属性以提醒它们已从视图模型的模型中更改时遇到了一个令人困惑的问题。例如,我有一个将 System.Drawing.Point 作为公共属性的模式。在视图模型中,我有一个公共属性,它返回一个字符串格式,以将点呈现为一个有效且易读的值。但是我认为我没有正确注册拦截,或者使用 Unity 拦截无法实现最终目标。
我已经用我的容器注册了拦截并设置了一个策略来拦截所有虚拟方法并设置规则以捕获所有设置的事件——尽管我对如何触发视图模型来检测/知道这一点感到困惑模型属性已更改。我想“简单”的解决方案是将视图模型专门绑定到模型上的属性,然后在 UI 中使用自定义格式化程序来确保正确显示值。
如果有人可以就统一拦截给出一些指示,那就太好了。
Container.AddNewExtension<Interception>();
PolicyDefinition policyDefinition =
Container.Configure<Interception>()
.SetInterceptorFor<MyModel>(new VirtualMethodInterceptor())
.SetInterceptorFor<MyViewModel>(new VirtualMethodInterceptor())
.AddPolicy("NotifyPolicy");
policyDefinition.AddMatchingRule(new PropertyMatchingRule("*", PropertyMatchingOption.Set));
public class MyModel
{
[NotifyPropertyChanged]
public virtual Point APoint { get; set; }
}
public class MyViewModel
{
private MyModel _myModel;
public MyViewModel()
{
_myModel = new MyModel { APoint = new Point(3, 2) };
// {12,8} is not reflected in the UI
_myModel.APoint = new Point(12, 8);
}
[NotifyPropertyChanged]
public virtual string ModelLocation
{
get
{
return string.Format("'{0}, {1}'", _myModel.APoint.X, _myModel.APoint.Y);
}
}
}
我使用了http://www.codeproject.com/Articles/140042/Aspect-Examples-INotifyPropertyChanged-via-Aspects中的 NotifyPropertyChangedAttribute 和 NotifyPropertyChangedHandler作为连接事情的例子;我已经包含了仅供参考的方法。
[AttributeUsage(AttributeTargets.Property)]
public class NotifyPropertyChangedAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new NotifyPropertyChangedHandler();
}
}
internal class NotifyPropertyChangedHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var result = getNext()(input, getNext);
if (input.MethodBase.Name.StartsWith("set_"))
{
var propertyName = input.MethodBase.Name.Substring(4);
var pi = input.Target.GetType().GetProperty(propertyName);
if (pi.HasAttribute<NotifyPropertyChangedAttribute>())
{
var baseType = input.Target.GetType().BaseType;
if (baseType != null)
{
var info =
baseType.GetFields(
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
.FirstOrDefault(f => f.FieldType == typeof(PropertyChangedEventHandler));
if (info != null)
{
var propertyChangedEventHandler = info.GetValue(input.Target) as PropertyChangedEventHandler;
if (propertyChangedEventHandler != null)
propertyChangedEventHandler.Invoke(
input.Target.GetType(), new PropertyChangedEventArgs(propertyName));
}
}
}
}
return result;
}
public int Order { get; set; }
}