About Me

Training

Develop With Passion® - Developer Bootcamp

Subscribe

Triggering events on UI components (WinForms)

Written March 03, 2009 at 15:37 MST Tagged .net 3.0, c sharp and programming

I am currently working on a large winforms application (most likely the last winforms app before I make the transition to WPF). I am writing the application in a top down fashion, which means I drive out the tests for the presenters, and then move down through the corresponding layers to get a good vertical slice of functionality. When it comes to the development of the user interface I am using a command based UI to allow me to easily drive the testing of the screens easily from a unit test. One thing that I often need to do, is cause a UI component to trigger one of its own events to see if the command in question will be triggered. In order to allow for a bit of “guidance” I wrote a class that allows me to quickly trigger events on UI components. The following code snippet shows a usage:

EventTrigger.trigger_event<Events.ControlEvents>(x => x.OnKeyPress(new KeyPressEventArgs('A')), target);

I am making use of an expression tree to determine which event I want the target control to raise. This is easily done because most (almost all) UI components in both the .Net framework and 3rd party Winforms libraries follow a convention of having a method named “OnEventName” which is usually a protected method that the control itself can call when it wants to raise its event. The EventTrigger class lives in my test utilities and for my current application I have a set of Events classes which correspond to some of the third party, and raw .net, control I want to raise events on, here is a trimmed down section of one of the events class:

public class Events

{

public interface ControlEvents : IEventTarget

{

void OnEnter(EventArgs args);

void OnKeyPress(KeyPressEventArgs args);

}

public interface FormEvents : ControlEvents

{

void OnActivated(EventArgs e);

void OnDeactivate(EventArgs e);

}

}


Again, this class lives in my test utility folder and it contains interfaces specific to control types that I want to raise events on. For each control interface, I will place the events (as needed) that I need to be able to trigger from my unit tests. There are multiple ways to get the correct method signature on these interface methods, I can use the Object Browser, Reflector, or ReSharper can generate them!! The point is, the interface contains a public method that is the identical signature for a corresponding protected method on the target control. This is really to help get intellisense about the event I want to raise along with the arguments to the method itself. This works with all component frameworks as their EventArgs classes are always made public as to be able to be consumed by the components that will be hosting them.
Let’s get to the interesting part of this. I mentioned earlier that I am an expression tree to ultimately raise the event. Let's take a look at the trigger_event method signature to get a little understanding of what it is doing:

static public void trigger_event(Expression<Action> expression_representing_event_to_raise, object target) where Target : IEventTarget

Notice I am making use of the IEventTarget interface to basically simply constrain the incoming expression to be one based on one of the interfaces that lives in the “Events” class. The first argument “Expression<Action> is an expression representing the code. The target argument is the actual control to raise the event on. Here is the entire body of the trigger_event method:

static public void trigger_event(Expression<Action> expression_representing_event_to_raise, object target) where Target : IEventTarget

{

var method_call_expression = expression_representing_event_to_raise.Body.downcast_to<MethodCallExpression>();

var method_args = get_parameters_from(method_call_expression.Arguments);

var method_name = method_call_expression.Method.Name;

var method = target.GetType().GetMethod(method_name, binding_flags);

Debug.Assert(target != null,"The target to raise the event on cannot be null");

Debug.Assert(method != null,"There is no method called {0}, on a {1}".format_using(method_name,target.GetType().proper_name()));

method.Invoke(target, method_args.ToArray());

}


This is test utility code, so I am able to make a lot of assumptions about how I am going to be consuming and using it. For starters I know that the ExpressionTree coming is is going to represent a MethodCallExpression. This post is only a small intro into the amazing concept of expression trees, if they are not something you are comfortable with, there is no time like the present to start playing around with them.
With a MethodCallExpression I have access to the MethodInfo object that contains information about the target method to call (this allows me to reflectively match upto the protected method on the target I want to raise the event on:

var method_name = method_call_expression.Method.Name;

var method = target.GetType().GetMethod(method_name, binding_flags);


Once I have the actual method to invoke, it still needs to be invoked with the correct arguments:

method.Invoke(target, method_args.ToArray());


The act of getting the arguments is the interesting part to this code (and a little gentle introduction to the world of ExpressionTrees for those of you who are not using them yet). The following line:

var method_args = get_parameters_from(method_call_expression.Arguments);

method_call_expression.Arguments is actually a collection of Expressions also. If you look back at the line of code that is using this the original trigger method, we’ll decompose it so that you can get a better idea of the expression tree created to represent the call to the event:

EventTrigger.trigger_event<Events.ControlEvents>(x => x.OnKeyPress(new KeyPressEventArgs('A')), target);


Expression tree are “tree based structures. This simple line of code actually constructs an ExpressionTree that consists of a:
Here is the complete code for the get_parameters_from method:

static IEnumerable<object> get_parameters_from(IEnumerable<Expression> parameter_expressions)

{

foreach (var expression in parameter_expressions)

{

if (can_handle(expression)) yield return get_value_from_evaluating(expression);

else cannot_handle(expression);

}

}


This method iterates over each Expression in the incoming set and attempts to expand it to an actual object value. The can_handle method simply makes use of an existing dictionary that has been populated at startup with handlers that know how to evaluate the appropriate Expression:

static EventTrigger()

{

expression_handlers = new Dictionary<ExpressionType, Func<Expression, object>>();

expression_handlers[ExpressionType.New] = instantiate_value;

expression_handlers[ExpressionType.MemberAccess] = get_value_from_member_access;

expression_handlers[ExpressionType.Constant] = get_constant_value;

}


The get_value_from_evaluating(expression) method is very simple, it just look into the dictionary using the NodeType of the current expression, and invokes the expression handler against the expression so that it can be evaluated:

static object get_value_from_evaluating(Expression expression)

{

return expression_handlersexpression.NodeType;

}


Lets start by looking at the simplest one of them all, the method that evaluates a ConstantExpression:

static public object get_constant_value(Expression expression)

{

return expression.downcast_to<ConstantExpression>().Value;

}


This method explicitly casts the incoming Expression to a ConstantExpression and then returns the expressions value. In our current example, that value will be the char ‘A’.
We’ll finish up by looking at the most involved one:

static object instantiate_value(Expression expression)

{

var new_expression = expression.downcast_to<NewExpression>();

var args = new_expression.Arguments.Select(constructor_argument_expression => get_value_from_evaluating(constructor_argument_expression));

return new_expression.Constructor.Invoke(args.ToArray());

}

In the second line we are actually evaluating each of the constructor arguments expressions one at a time and having them also evaluated by the get_value_from_evaluating method. Because of the nested nature of expression trees, depending on the type of Expression that was passed in, this handles recursive traversal of the expression.
Once all of the arguments to the constructor have been evaluated, we can then invoke the expressions Constructor (which is a ConstructorInfo) to create the item. In our example here, it will cause the creation of a new KeyPressEventsArgs with the character of ‘A’ (the character was evaluated using the ConstantExpression we discussed earlier).
When it comes to testing a new control I can just create a new nested interface in my Events class, add public versions of the protected methods that I want to invoke (along with the correct arguments) and then I’m off to the races!!
Develop With Passion