Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a single event handler for multiple controls with different event handler delegates

I have a function, void Validate(), that contains all my validation logic for a window.

I can't simply register this as an event handler because it doesn't accept the parameters required by the event handler delegates. Additionally different types of controls have different signatures so I can't just have Validate match one signature while ignoring their contents.

Here is a small example of what I've setup

    txt1.TextChanged += Validate_TextChange;
    password1.PasswordChanged += Validate_RoutedEvent;
    txt2.TextChanged += Validate_TextChange;

    txt3.TextChanged += Validate_TextChange;
    password2.PasswordChanged += Validate_RoutedEvent;
    txt4.TextChanged += Validate_TextChange;


void Validate_RoutedEvent(object sender, RoutedEventArgs e)
{
    ValidateOptions();
}

void Validate_TextChange(object sender, TextChangedEventArgs e)
{
    ValidateOptions();
}

public void ValidateOptions()
{
   //Actual validation here
}

This just shows 2 examples, more controls could have even more signatures. Is there any better way of getting all event handlers to call a function in a case where I don't care about the arguments being passed?


EDIT: I like the option proposed by Jon to add the parameters and simply ignore them. That does solve most of the problem but anytime I want to call this function directly, such as to manually trigger validation, I then have to include dummy arguments to satisfy the compiler. ValidateOptions(this, new EventArgs())

The suggestion Dan made, to use anonymous functions, would handle this but isn't as clean when associating the event handlers.

It doesn't appear that either solution lets you register a function as an event handler while ignoring the signature while also preserving the ability to call the function without creating dummy arguments but there are multiple ways to get pretty close.


EDIT:

Here is the updated example implementing Jon's solution for generic event handling but keeping a 0 parameter function that can be called directly

txt1.TextChanged += ValidationEvent;
password1.PasswordChanged += ValidationEvent;
txt2.TextChanged += ValidationEvent;

txt3.TextChanged += ValidationEvent;
password2.PasswordChanged += ValidationEvent;
txt4.TextChanged += ValidationEvent;


//Single event handler accepting EventArgs, which is the base class
//for all more-specific event classes
void ValidationEvent(object sender, EventArgs e)
{
    //Ignores arguments and calls 0 argument ValidateOptions
    ValidateOptions();
}

//0 argument function that performs actual validation and can be called
//directly from other functions without the need to pass in a fake sender
//and eventargs parameter
public void ValidateOptions()
{
   //Actual validation here
}
like image 767
Eric Avatar asked Nov 18 '11 23:11

Eric


2 Answers

You can have a single method which ignores the parameters:

public void ValidateOptions(object sender, EventArgs e)
{
}

The compiler will allow a conversion from the ValidateOptions method group to any delegate type following the normal event pattern such that the first parameter is sender and the second parameter is some type derived from EventArgs.

like image 173
Jon Skeet Avatar answered Oct 29 '22 03:10

Jon Skeet


You can use lambda expressions to reduce the amount of code you write for wrappers, though, behind the scenes, it's still creating wrapper methods to discard the parameters.

txt3.TextChanged += (s,e) => ValidateOptions();
password2.PasswordChanged += (s,e) => ValidateOptions();
txt4.TextChanged += (s,e) => ValidateOptions();
like image 32
Dan Bryant Avatar answered Oct 29 '22 01:10

Dan Bryant