Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining the caller inside a setter -- or setting properties, silently

Given a standard view model implementation, when a property changes, is there any way to determine the originator of the change? In other words, in the following view model, I would like the "sender" argument of the "PropertyChanged" event to be the actual object that called the 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
}

Alternatively, is it possible to apply CallerMemberNameAttribute to a property setter?

like image 208
McGarnagle Avatar asked Nov 01 '13 23:11

McGarnagle


2 Answers

If I understood correctly, you're asking about the caller of the setter. That means, the previous method call in the call stack before getting to the setter itself (which is a method too).

Use StackTrace.GetFrames method for this. For example (taken from 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
  }
}

The output:

Main
nExecuteAssembly
ExecuteAssembly
RunUsersAssembly
ThreadStart_Context
Run
ThreadStart

Basically, what you're asking for would be stackFrames[1].GetMethod().Name.

like image 55
Tengiz Avatar answered Nov 14 '22 21:11

Tengiz


My first approach to your problem would be to derive from PropertyEventArgs. The new class would have a member called, for instance PropertyChangeOrigin in addition to PropertyName. When you invoke the RaisePropertyChanged, you supply an instance of the new class with the PropertyChangeOrigin set from the information gleaned from the CallerMemberName attribute. Now, when you subscribe to the event, the subscriber could try casting the eventargs to your new class and use the information if the cast is successful.

like image 5
Boluc Papuccuoglu Avatar answered Nov 14 '22 20:11

Boluc Papuccuoglu