1

I want my C# code to call an event whenever a value is assigned to my object.

How exactly would I need to go about that?

class MyClass {

  ManualResetEvent mre;

  public MyClass() {
    mre = new ManualResetEvent(false);
    Data = null;
  }

  public object Data { get; set; }

  void DataSet(object sender, EventArgs e) {
    Console.WriteLine("object Data has been set.");
    mre.Set();
  }

}

Delegates don't seem to be what I need. An event, maybe? How would I write such an event, if so?

MyClass mc;

void processA() {
  mc = new MyClass();
  mc.Data = GetDataFromLongProcess();
}
Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132

6 Answers6

5
private object data;
public object Data {
    get { return data;}
    set {
        if(value != data) {
            data = value;
            OnDataChanged();
        }
    }
}
protected virtual void OnDataChanged() {
    EventHandler handler = DataChanged;
    if(handler != null) handler(this, EventArgs.Empty);
}
public event EventHandler DataChanged;

then hook any code to the DataChanged event. For example:

MyClass mc = ...
mc.DataChanged += delegate {
    Console.WriteLine("new data! wow!");
};
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks. I knew it was something simple. I just had a brain block. –  Aug 22 '11 at 20:42
  • What would need to be changed in the `DataChanged` method declaration so that I could write a handler method that takes a custom data type? (i.e. `if (handler != null) handler(this, new MyEventArgs(Data));` (I already have the `MyEventArgs` class written, I just don't know how to declare the `DataChanged` method to implement it. –  Aug 22 '11 at 20:55
  • 1
    @jp2code You can declare it as `public event EventHandler DataChanged;` – dlev Aug 22 '11 at 20:56
2

If you want to fire an event when your property is set, you would do something like this:

 public event Action OnDataChanged;

 protected object _data = null;
 public object Data
 {
     get { return _data; }
     set
     {
         _data = value;
         if(OnDataChanged != null)
            OnDataChanged();
     }
 }

Then you would simply wire up event handlers to your object like so:

 mc = new MyClass();
 mc.OnDataChanged += delegate() { Console.WriteLine("It changed!"); };
 mc.Data = SomeValue();
Tejs
  • 40,736
  • 10
  • 68
  • 86
  • 1
    In most C# references, `OnFoo` is the method (usually `protected virtual`) that *invokes* the `event` named `Foo` - not the name of the event itself. This is, of course, merely convention and not a rule. Also note that *strictly* speaking you should capture the field into a variable before the null-check, to avoid a threading edge-condition that can cause a `NullReferenceException`. – Marc Gravell Aug 22 '11 at 20:45
  • Good point. Honestly, I dont write enough events to have run afoul of good convention yet =D – Tejs Aug 22 '11 at 20:46
  • Actually, in terms of *bindings* there is a good reason to follow the convention: `PropertyDescriptor` will *check* for an event named `*Changed` (not `On*Changed`) and use that to support full data-binding. This also applies to any other uses of the default `PropertyDescriptor` API. – Marc Gravell Aug 22 '11 at 20:48
  • @Marc Good point about the threading edge-condition. You do end up with the alternate (though much more easily dealt-with) edge-condition of a handler unsubscribing after the assignment. Good thing all your handlers are written to gracefully deal with being called under those circumstances, right? :) – dlev Aug 22 '11 at 20:49
  • @dlev yes, that one remains - a pain, isn't it? – Marc Gravell Aug 22 '11 at 20:50
2

I think you're on the right track with an event-based model. Also take a look at the Observer pattern (which is the basis for .Net delegates and events underneath it all, as I understand):

http://www.dofactory.com/Patterns/PatternObserver.aspx

But the bottom line, as the other useful answer so far (Mr. Gravell's implementation) indicates, you're going to have to have code IN the setter to get it hooked up. The only alternative would be to poll the value for changes, which just smells bad to me.

Chris B. Behrens
  • 6,255
  • 8
  • 45
  • 71
1

you could implement INotifyPropertyChanged (this is more or less a event) or you could take your class a Action (Trigger) and call this, whenn the property changed.

Just don't use automatic properties but a concrete setter and call your event/trigger from there.

Random Dev
  • 51,810
  • 9
  • 92
  • 119
1

Conceptually, you would define an event in your class, and in your property set blocks, you would invoke the event with the necessary arguments to determine what just happened.

Jeremy Holovacs
  • 22,480
  • 33
  • 117
  • 254
1
 public event SomeDelegateThatTakesIntAsParameter myEvent;
 void SetData(int data)
 {
   if(myEvent!= null)
     myEvent(data)
 }
aero
  • 262
  • 2
  • 10