我使用PostSharp的NotifyPropertyChanged方面。
我遇到需要手动触发PropertyChanged
事件的情况,因为我的用例对于PostSharp来说似乎太复杂了。以下是我的视图模型中的相关摘录:
private RelayCommand _authenticateCommand;
[IgnoreAutoChangeNotificationAttribute]
public ICommand AuthenticateCommand
{
get { return _authenticateCommand ?? (_authenticateCommand = new RelayCommand(Authenticate, _ => IsNotAuthenticated)); }
}
private void Authenticate(object obj)
{
var result = _dialogService.OpenAuthenticationDialog();
if (result.HasValue && result.Value)
{
_mainViewModel.Update();
}
// At this point I need to trigger NotifyPropertyChanged for IsNotAuthenticated,
// because the authentication dialog causes changes
// to the _authenticationViewModel's IsLoggedIn property.
}
public bool IsNotAuthenticated
{
get
{
return !_authenticationViewModel.IsLoggedIn;
}
}
如上面代码中的评论所述,当验证对话框完成后,我需要触发NotifyPropertyChanged
的{{1}}事件,因为对话框可能会更改值。
阅读the documentation,似乎应该很容易:
目标类可以通过实现NotifyPropertyChangedAttributeTargetClass类中记录的一个或多个成员来自定义NotifyPropertyChangedAttribute方面。
和NotifyPropertyChangedAttributeTargetClass.OnPropertyChanged页面:
引发PropertyChanged事件。如果此方法已存在于目标代码中,则NotifyPropertyChangedAttribute方面将使用它来引发PropertyChanged事件。否则,方面将把方法引入目标类。
很好,所以我尝试在我的视图模型中实现一个空的IsNotAuthenticated
方法,认为它将被PostSharp的版本取代,但唉,它只是打破了所有通知逻辑。这是在我替换OnPropertyChanged
之前生成的代码的外观:
OnPropertyChanged
这就是它的照顾方式:
protected void OnPropertyChanged(string propertyName)
{
this.<>z__aspect0.OnPropertyChanged(propertyName);
}
测试代码,它适用于第一种情况,而不是第二种情况。因此,我执行空protected void OnPropertyChanged(string propertyName)
{
this.<>z__aspect0.OnMethodEntry(null);
try
{
}
finally
{
this.<>z__aspect0.OnMethodExit(null);
}
}
会导致该功能停止工作。
我猜文档在撒谎?它明确地说(强调我的)
如果目标代码中的此方法已存在,则NotifyPropertyChangedAttribute方面将使用它来引发PropertyChanged事件。&#34; - 但上面生成的代码和我的测试说不然。
我在此期间做了什么&#34;在此期间,直到我弄清楚我是什么或者PostSharp做错了,创造我自己的方面,就像这样:
OnPropertyChanged
然后在我的班级用它标记一个方法:
[Serializable]
class PropertyChangedTriggerAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
var inpc = args.Method.DeclaringType;
if (inpc == null) throw new InvalidOperationException("PropertyChangedTriggerAttribute used on an object that doesn't have an OnPropertyChanged(System.String) method.");
var opc = inpc.GetMethod("OnPropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic);
var value = (string) args.Arguments.GetArgument(0);
opc.Invoke(args.Instance, new object[] { value });
}
}
现在我可以打电话给它,然后它会为我触发[PropertyChangedTrigger]
private void TriggerOnPropertyChanged(string propertyName)
{
}
。
关于我在这里做错了什么的任何想法?有谁让这个为他们工作?
答案 0 :(得分:3)
我认为您误解了以下内容:
引发PropertyChanged事件。如果此方法已存在于目标代码中,则NotifyPropertyChangedAttribute方面将使用它来引发PropertyChanged事件。否则,方面将把方法引入目标类。
如果该方法已存在于类中,NotifyPropertyChangedAttribute将使用它。这意味着该方法需要执行实际通知,因为方面正在使用它而不是它自己的实现。因此,您需要引发PropertyChanged事件。这意味着您需要自己实现INotifyPropertyChanged接口:
[NotifyPropertyChanged]
public class TestClass : INotifyPropertyChanged
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void DoSomething()
{
this.Property1 = 42;
this.OnPropertyChanged( "Property2" );
}
protected void OnPropertyChanged( string propertyName )
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if ( handler != null )
handler( this, new PropertyChangedEventArgs(propertyName) );
}
}
class Program
{
static void Main(string[] args)
{
TestClass test = new TestClass();
INotifyPropertyChanged inpc = Post.Cast<TestClass, INotifyPropertyChanged>(test);
inpc.PropertyChanged += ( s, ea ) =>
{
Console.WriteLine("Notification received for {0}", ea.PropertyName);
};
test.DoSomething();
}
}
这样,它可以按照您的意愿工作,即输出为:
Notification received for Property2
Notification received for Property1
请注意,顺序是这样的,因为当 DoSomething 方法退出时,会自动(通过方面)引发 Property1 更改。