tags:

views:

684

answers:

5

Situation: C#, .NET 3.5, WinForms

Objective: Form1 has a Button that can be enabled via the constructor. I.E. the button will only be shown if I call new Form1(true). We'd like to be able to pass a method via some param from Form2 to Form1 (doesn't have to be on Form1's constructor), and when Form1.Button1 is pressed, Form2.<SomeMethod> should be executed.

We know that we could create a Delegate/Event in Form1 and from Form2 do something like:

Form1.SomeDelegate += new ..... (MyMethodInForm2);

…and then in Form1_ButtonClick we fire the event which, in turn will do the magic in Form2.

But we were wondering if there was a more elegant/new/modern version (Anonymous Methods? Lambda Expressions? Etc.) to accomplish this.

The idea is that "any" form could instanciate a Form1 class and pass its own method to be executed when Form1's button is clicked; but instead of a callback to the caller (form2,3,..n), Form1 executes the passed function (which possibly resides inside the caller). We really don't need these functions to have parameters for now.

Note: The code samples contain simple variable/object names and are not taken from real life, please ignore the simplicity.

UPDATE Sorry for not being more specific, I think that I'll keep using the Delegate/Event model, but for reference, here's what I think is a better description of the situtation:

Form1 is a generic form, that accepts a list of items and displays them. We may pass Employee types or Person Types or any "T". It works ok. We received a requirement from a customer, asking if it was possible to add an optional button to that little Form1 that, if clicked, it will open another form/execute some method.

That way, if I am using Form1, I could -at runtime- tell the button to open the EmployeeForm, whereas if I am using Form1, the very same button could open the form PersonForm. Now opening a Form is not the only use we'd have for that button, but that's the caller's problem.

Right now, what I've done is what we've said: delegate/event on that Form1 and on the "calling" form we do a Form1.theEvent += stuff, to subscribe to the event. I just wanted to know if there was a better way to accomplish this, as this is how we'd do it in .NET 2.0 and we have just started using .NET 3.5.

+1  A: 

Not totally sure what you mean with the form stuff, but you can send in a Func. For example:

public class MyForm<T>
{

   private readonly Func<T, bool> predicate;

   public MyForm(Func<T, bool> predicate) { this.predicate = predicate }

   private void SomeMethod()
   {
       bool result = predicate();
       // Do something
   }
}

var form = new MyForm(x => x.Number < 5);
Svish
You can also use Action<T> which will always return void or Predicate<T> which will always return bool
Jabezz
A: 

1st:you should declare a public event in Form1.
2nd:you should invoke the event where it is sent to Form1 like Button1_Click

Behrooz
Jon, if he needs to start doing that in some special time or it is not used always passing it as a parameter or in a lambda expression can decrease speed.
Behrooz
+1  A: 

It sounds like you're describing the same thing twice.

Subscribing to an event does exactly this - passes a function to Form1, which then executes the function when the event is raised.

You could subscribe to the event using a lambda expression if you want, but you don't have to.

Of course you could put the delegate as a Form1 constructor parameter if you wanted, but I don't see much advantage to doing so in this case.

In short: I think normal events do everything you need. If you have a requirement which events don't handle, please give more information.

Jon Skeet
I guess the aesthetics of it depend on whether Form1 ALWAYS uses this kind of delegate. If so, passing something in the constructor makes a tiny bit more aesthetic sense as it binds the requirement into the API. However it is optional and this form can be used in other ways then as Jon states there is no reason to do this another way.
Quibblesome
A: 

From what I can tell, Form2 is a non-modal dialog that Form1 can update. However Form2 might not have been created yet.

The obvious way to accomplish updating Form2 is using the event model as you have, using Composition and passing Form1 into its constructor.

You could use a delegate and store that but I can't see how that is preferably to passing a reference to the parent Form in.

If you want Form2 to update any type then a simple interface would solve the problem.

Chris S
A: 

Another approach is to expose the Click event of the button by defining a "proxy-event" on the generic form:

public class MyForm<T> : Form
{

    public event EventHandler MyClick
    {
        add { this.theButton.Click += value; }
        remove { this.theButton.Click -= value; }
    }

    // ...
}
Johan Kullbom