views:

2002

answers:

3

I have an application that has a main form and uses an event handler to process incoming data and reflect the changes in various controls on the main form. This works fine.

I also have another form in the application. There can be multiple instances of this second form running at any given time.

What I'd like to do is have each instance of this second form listen to the event handler in the main form and update controls on its instance of the second form.

How would I do this?

Here's some sample code. I want to information from the_timer_Tick event handler to update each instance of SecondaryForm.

public partial class Form1 : Form
{
    Timer the_timer = new Timer();
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        the_timer.Tick += new EventHandler(the_timer_Tick);
        the_timer.Interval = 2000;
        the_timer.Enabled = true;
    }

    void the_timer_Tick(object sender, EventArgs e)
    {
        // I would like code in here to update all instances of SecondaryForm
        // that happen to be open now.
        MessageBox.Show("Timer ticked");
    }

    private void stop_timer_button_Click(object sender, EventArgs e)
    {
        the_timer.Enabled = false;
    }

    private void start_form_button_Click(object sender, EventArgs e)
    {
        SecondaryForm new_form = new SecondaryForm();
        new_form.Show();
    }
}
+4  A: 
class SecondForm
{
  private FirstForm firstForm;

  public SecondForm()
  {
    InitializeComponent();
    // this means unregistering on form closing, uncomment if is necessary (anonymous delegate)
    //this.Form_Closing += delegate { firstForm.SomeEvent -= SecondForm_SomeMethod; };
  }

  public SecondaryForm(FirstForm form) : this()
  {
    this.firstForm = form; 
    firstForm.Timer.Tick += new EventHandler(Timer_Tick);
  }

  // make it public in case of external event handlers registration
  private void Timer_Tick(object sender, EventArgs e)
  {
    // now you can access firstForm or it's timer here
  }
}

class FirstForm
{
  public Timer Timer
  {
    get
    {
      return this.the_timerl
    }
  }

  public FirstForm()
  {
    InitializeComponent();
  }

  private void Button_Click(object sender, EventArgs e)
  {
    new SecondForm(this).ShowDialog(); // in case of internal event handlers registration (in constructor)
    // or
    SecondForm secondForm = new SecondForm(this);
    the_timer.Tick += new EventHandler(secondForm.Timer_tick); // that method must be public
  }
abatishchev
Don't forget to remove the event handler when the second form is closed, otherwise you could potentially have a reference leak...
Rowland Shaw
Shouldn't all your references to SecondForm be SecondaryForm? And what would SomeEvent look like in the main form that I posted?
Dave
Yea, I mean SecondForm = SecondaryForm. For example, you can make Timer to be public or crate a property for access it, and listen not FistForm events, but it's timer events: See my code, I'll edit it
abatishchev
I'm getting "An object reference is required for the non-static field, method, or property 'TestApp.SecondaryForm.Timer_Tick(object, System.EventArgs)'" when I try to assign the event handler to the_timer.Tick += new EventHandler(SecondaryForm.Timer_Tick);
Dave
Sorry, my mistake. Use EventHandler(secondForm.Timer_tick) instead of SecondForm.Timer_tick. Also I changed a property for Timer.
abatishchev
Could you please mark my post as an answer, if it is.
abatishchev
A: 

I guess you can make SecondaryForm take in the parent form in the constructor, and the add an event handler in the constructor.

private void start_form_button_Click(object sender, EventArgs e)
{
    SecondaryForm new_form = new SecondaryForm(this);
    new_form.Show();
}

In SecondaryForm.cs:

public SecondaryForm(ISomeView parentView)
{
    parentView.SomeEvent += .....
}
Kjetil Watnedal
+1  A: 

Consider using loosely coupled events. This will allow you to couple the classes in such a way that they never have to be directly aware of each other. The Unity application block comes with an extension called EventBroker that makes this very simple.

Here's a little lick of the sugar:

public static class EVENTS
{
    public const string UPDATE_TICKED = "event://Form1/Ticked";
}

public partial class Form1 : Form
{
    [Publishes(EVENTS.UPDATE_TICKED)]
    public event EventHandler Ticked; 

    void the_timer_Tick(object sender, EventArgs e)
    {
        // I would like code in here to update all instances of SecondaryForm
        // that happen to be open now.
        MessageBox.Show("Timer ticked");
        OnTicked();
    }

    protected virtual void OnTicked()
    {
        if (Ticked == null) return;
        Ticked(this, e);
    }
}

public partial class SecondaryForm : Form
{
    [SubscribesTo(EVENTS.UPDATE_TICKED)]
    private void Form1_Ticked(object sender, EventHandler e)
    {
        // code to handle tick in SecondaryForm
    }
}

Now if you construct both of these classes using Unity, they will automatically be wired together.

Michael Meadows