我一直在对现有应用程序进行重构,并且尝试在属性上使用 Attribute 来使用 Unity 拦截触发 NotifyPropertyChanged 事件。我到了事件触发的地步,但控件没有更新。
我不确定它是否正确调用了事件,所以在我的 ViewModelBase 上我创建了一个调用属性更改事件的 DispatchPropertyChanged 方法。此方法用于在直接从视图模型调用时启动属性更改,但是当从通过拦截处理程序内的反射检索的视图模型调用时,它不起作用。
我插入了指向https://www.dropbox.com/s/9qg2n0gd2n62elc/WPFUnityTest.zip的链接。如果您打开此解决方案并运行应用程序,然后单击“重置”按钮,您将看到“正常”文本框更新,但“Unity”文本框没有更新。
如果在 MainWindowViewModel 的第 65 行和 NotifyPropertyChangedHandler 的第 53 行放置断点,您将看到处理程序正在工作,正在调用调度方法,并且正在调用事件。但是,只有“正常”一个更新。
关于为什么“Unity”文本框没有更新的任何帮助都会很棒,谢谢!
阿曼达
编辑:
很抱歉最初没有包括这个,我真的不知道问题出在哪里。这是下面正确的拦截行为的原始代码:
public class NotifyPropertyChangedHandler : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var npcAttribute = getNotifyPropertyChangedAttributeForSetter(input) as NotifyPropertyChangedAttribute;
if (npcAttribute != null)
{
if (npcAttribute.TimingOption == PropertyChangedTiming.Always||
shouldRaiseEvent(input))
{
raiseEvent(input);
}
}
return getNext()(input, getNext);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return new[] { typeof(INotifyPropertyChanged) };
}
public bool WillExecute { get { return true; } }
private object getNotifyPropertyChangedAttributeForSetter(IMethodInvocation input)
{
if (!input.MethodBase.Name.StartsWith("set_"))
{
return null;
}
return input.MethodBase.ReflectedType.GetProperty(input.MethodBase.Name.Substring(4))
.GetCustomAttributes(true).SingleOrDefault(attr => attr.GetType() == typeof (NotifyPropertyChangedAttribute));
}
private void raiseEvent(IMethodInvocation input)
{
raiseEvent(input, new PropertyChangedEventArgs(input.MethodBase.Name.Substring(4)));
}
private void raiseEvent(IMethodInvocation input, PropertyChangedEventArgs eventArgs)
{
var viewModel = input.Target as ViewModelBase;
if (viewModel != null)
{
viewModel.DispatchPropertyChangedEvent(eventArgs.PropertyName);
}
}
private static bool shouldRaiseEvent(IMethodInvocation input)
{
var methodBase = input.MethodBase;
if (!methodBase.IsSpecialName || !methodBase.Name.StartsWith("set_"))
{
return false;
}
var propertyName = methodBase.Name.Substring(4);
var property = methodBase.ReflectedType.GetProperty(propertyName);
var getMethod = property.GetGetMethod();
if (getMethod == null)
{
return false;
}
var oldValue = getMethod.Invoke(input.Target, null);
var value = input.Arguments[0];
return (value == null) ? oldValue !=null :
!value.Equals(oldValue);
}
}