Skip to main content
gamedev.net
🔒 Locked

[.net] Events

Started by yaroslavd 9 replies 1.8k views
Original Post
yaroslavd
yaroslavd
Hi, guys. I am trying to learn events and I get the idea and everything, but the actual implementation is kinda hard to get my head around. In my particular situation, I have a Table class and a Display class. The user can input a number into x_input, which is a NumericUpDown control. I want a method in Table which gets called when x_input.ValueChanged fires. I whipped up the folliwng code but I'm really not sure if it's right. Can someone please check the accuracy? Thanks in advance.

class Display
{
  double x;
  Table table;

  public void UpdateX(object sender, EventArgs args)
  {
     this.x = table.x_input.Value;
  }
}

class Table
{
  public double x_input;
  Display disp;

  Table()
  {
     x_input.ValueChanged+=new EventHandler(disp.UpdateX);
  }
}

Once again, thanks in advance. I'm just a little confused after all I read about events and would like to know if I have a good understanding.
ernow
ernow
I think what you want is:

class Display{  private double _x;  private Table _table;  public Display()  {    _table.XChanged += new ValueChangedHandler(this._x_ValueChanged);  }  private void _x_ValueChanged(object sender, ValueChangedEventArgs e)  {    _x = e.NewValue;  }}class Table{  private double _x;  public double X  {    get    {       return _x;    }    set    {      OnValueChanged(_x, value);      _x = value;    }   }  public event ValueChangedHandler ValueChanged;  protected void OnValueChanged(double oldValue, double newValue)  {    if(ValueChanged != null)    {      ValueChanged(this, new ValueChangedEventArgs(oldValue, newValue);    }  }  class ValueChangedEventArgs : EventArgs  {    private double _oldValue;    private double _newValue;    public double OldValue    {      get      {        return _oldValue;      }      }    public double NewValue    {      get      {        return _newValue;      }    }    public ValueChangedEventArgs(double oldValue, double newValue)    {      _oldValue = oldValue;      _newValue = newValue;    }  }  delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);}


Cheers

[Edited by - ernow on January 21, 2005 3:49:07 AM]
yaroslavd
yaroslavd
Is that really necessary, though? NumericUpDown already has a built-in ValueChangedEvent. I was thinking that once I knew the value changed, then it's no problem to just poll the control for the value. Right?
ernow
ernow
No, you don't need all of it. I just gave you an example of how events can be implemented. Sure you can poll the value but you have to be carefull though, in multi threaded apps, information stored in an EventArgs object is represents the state that triggered the event, whereas polling might show state that was changed in the meantime by another thread.

Cheers
yaroslavd
yaroslavd
Thanks. I think I understand events better now. However, I was wondering if MY way looks right to you. Also, I don't think I have to worry about the state of the value because my app is single-threaded and ValueChanged only sends out the generic EventArgs anyway. I just need to catch the event in order to KNOW that the value was changed.

So basically can you quickly skim over my code (it's not long at all) and tell me what you think? Thanks a lot.
ernow
ernow
Well... part of your code does not comply to your specs. You stated: "I want a method in Table which gets called when x_input.ValueChanged fires." It is a function in the Display class that gets called. This is also my main problem with your setup: the Table class knows too much about the Display class. Perhaps the Display class should be a inner class of Table.

Make the fields private and provide propertie methods.

Nothing realy wrong.

Cheers
yaroslavd
yaroslavd
Oh geez, I really got the two confused. I'm sorry. This is what I meant to do:

class Table{  double x;  Display disp;  public void UpdateX(object sender, EventArgs args)  {     this.x = disp.x_input.Value;  }}class Display{  public double x_input;  Table table;  Display()  {     x_input.ValueChanged+=new EventHandler(table.UpdateX);  }}


Sorry about that. Also, the thing with the private fields and public properties, I'll definetely do that. I just didn't want to clutter this messageboard with such things - this is more of pseudocode.

Oh, and one more thing - is it possible to do this in Table constructor?

Table(){  display.x_input.ValueChanged+=new EventHandler(this.UpdateX);}


You know, instead of doing the same in the Display constructor. Once again, thanks.
ernow
ernow
I think you mean the double in the Display class to be of NumericUpDown type instead of a double...


Still, the Table is hooking up the eventhandler of the Display, I always let the class subscribe itself. Your second piece of code does exactly that. And that is valid as long as you pass the right info to the constructor.

cheers
yaroslavd
yaroslavd
Thank you SO much. If I could raise your rating any more, I would. I would like to ask just ONE last question (promise [wink]). Is there any way to fire an event that's not implemented in your class and isn't public? Specifically, I want x_input.ValueChanged to be fired in Table constructor. Right now I have to x_input.UpValue; x_input.DownValue. I'd like to just say something like x_input.x_input.Fire(). Is there a way to do that?

Thanks again. I can't express my gratitude enough for dealing with such a newb.
ernow
ernow
Well after such praise it's hard to deny, isn't it... :) An event can/should be compared to a field. So when it is private: it is. When it is public: it is. So when you want to raise the event you will have to access its 'raiser'. The raiser is the OnValueChanged function in my example. (A common implementation so you don't raise the event anywhere in code but just call this function). Normally this function is protected and thus can only be called from the class itself and its descendants. BUT you could make it public.

However, I strongly advise against that. It is the class itself that knows about the state change and therefore is the only one that can decide to raise the event.

Hope this helps.

Cheers
ernow
ernow
Oh, BTW: Are you sure you want to raise the event or do you want to call the handler as a sort of initialisation? If so, you don't raise the event, you call the handler.

Many times, problems like these are caused by not having distributed the responsibilities of the classes in a correct way...

Cheers

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.