确定setter中的调用者 – 或者静默设置属性

给定标准视图模型实现,当属性更改时,有没有办法确定更改的发起者? 换句话说,在下面的视图模型中,我希望“PropertyChanged”事件的“sender”参数成为调用Prop1 setter的实际对象:

 public class ViewModel : INotifyPropertyChanged { public double Prop1 { get { return _prop1; } set { if (_prop1 == value) return; _prop1 = value; // here, can I determine the sender? RaisePropertyChanged(propertyName: "Prop1", sender: this); } } private double _prop1; // TODO implement INotifyPropertyChanged } 

或者,是否可以将CallerMemberNameAttribute应用于属性设置器?

如果我理解正确,你就会询问二传手的来电者。 这意味着,前一个方法在进入setter本身之前调用了调用堆栈(这也是一个方法)。

为此使用StackTrace.GetFrames方法。 例如(摘自http://www.csharp-examples.net/reflection-callstack/ ):

 using System.Diagnostics; [STAThread] public static void Main() { StackTrace stackTrace = new StackTrace(); // get call stack StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) // write call stack method names foreach (StackFrame stackFrame in stackFrames) { Console.WriteLine(stackFrame.GetMethod().Name); // write method name } } 

输出:

 Main nExecuteAssembly ExecuteAssembly RunUsersAssembly ThreadStart_Context Run ThreadStart 

基本上,你要的是stackFrames[1].GetMethod().Name

我的第一个解决问题的方法是从PropertyEventArgs派生。 除了PropertyName之外,新类将有一个名为PropertyChangeOrigin的成员。 当您调用RaisePropertyChanged ,您将从CallerMemberName属性中收集的信息中提供PropertyChangeOrigin设置的新类的实例。 现在,当您订阅该事件时,订阅者可以尝试将eventargs为您的新类,并在转换成功时使用该信息。

你看过CallerMemberName msdn页面了吗?

我正在使用它来避免做RaisePropertyChanged("some_name_here"); 通过在基类中使用它,然后所有属性只调用RaisePropertyChanged();

我相信它也可以用在制定者中……

编辑:

根据评论问题,这里有一些代码可以做到(傻,但仍然会做的问题:)

 public int some_int { get { return _someInt; } set { _someInt = value; var v = check_sender(); Console.Out.WriteLine("in the setter of {0}", v); } } private int _someInt; private string check_sender([CallerMemberName]string property = "") { return property; } 

然后,如果在二传手中,我会写:

 some_int = 7; // obviously, any number will cause it to fire 

你将进入输出(注意中间行,添加其余部分,所以你会看到它是一些控制台输出):

 'WPF MVVM for SO.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. in the setter of some_int 'WPF MVVM for SO.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. 

这是我一直用作INotifyPropertyChanged和我的View Models之间的中间点:

 public class NotifyOnPropertyChanged : INotifyPropertyChanged { private IDictionary _arguments; public event PropertyChangedEventHandler PropertyChanged = delegate { }; public void OnPropertyChanged([CallerMemberName] string property = "") { if(_arguments == null) { _arguments = new Dictionary(); } if(!_arguments.ContainsKey(property)) { _arguments.Add(property, new PropertyChangedEventArgs(property)); } PropertyChanged(this, _arguments[property]); } } 

这里有两件事。 它使用[CallerMemberName]属性设置属性名称。 这使用法语法如下:

 public string Words { set { if(value != _words) { _words = value; OnPropertyChanged( ); } } } 

除此之外,它将PropertyChangedEventArgs对象存储在字典中,因此对于经常设置的属性,它不会被创建很多次。 我相信这可以解决你的问题。 祝好运!

每当我必须将额外信息传递到VM时,我在使用命令方面取得了巨大成功:

命令,RelayCommands和EventToCommand