shunted the tedious wiring up of events and handlers into helpers (or a “framework”)

Unfortunately, the application was intended to work at our established customers’ sites, so I couldn’t depend on WPF, or even .NET 2.0 – it’s 1.1 all the way.

The Goal

I’ll demonstrate with a simpler app than the one from work, but will cover the the relevant concepts. For the purpose of this post, I’ll be writing a book-finding app. The user will be able to enter a substring to use to search a database; the matching entries will be displayed in a ListBox and when one of them is selected, some notes will be displayed in a TextBox.

I didn’t want to have to riddle my ViewModel with +=s just to be able to react to button presses and item selections from the view. I wanted to write something like:

and have the method run when the Click event on the Find button was raised. The method should use the value of the Text property of the Title TextBox to find a list of books and put them in the Items collection on the BookList ListBox.

Wiring up Event Handlers

I created a ViewModelBase class to handle all the infrastructure, so the BookListViewModel code could focus on app-related functions. The first thing ViewModelBase.BindToView does is seek out event handlers to bind to on the supplied View (which can be any Controller object):

AllControlsDescendingFrom recursively looks through all the controls rooted at the View and returns them as a flat list. EventHandlers uses reflection to locate public methods on the ViewModel that have event-like signatures:

Note the last line. I’d originally just checked that the second parameter was of type EventArgs. This worked for many event types, like the Click event on a Button and the SelectedIndexChanged event on a ListBox, but failed to match others, such as a TextBox’s KeyPress event:

FindEventToListenTo looks through the allControls list. If there’s a control with name Controlname and an event Eventname, it will bind to a handler named ControlnameEventname. For example method SearchClick would be hooked up to the Click event on a control called Search.

This is pretty straightforward, with two exceptions. Creating the delegate to wrap the ViewModel method was a little tricky – I had to reference the specific EventHandlerType that matched the event. Similarly to the EventArgs problem above, I’d originally tried to create an EventHandler, which failed for certain events.

The last piece is the ControlAttributeName method, which builds the desired attribute (in this case an event) name from a control and the ViewModel member that we want to bind to. The method assumes that the name of the ViewModel member (the handler) will start with the name of the control. If there’s a match, it returns the rest of the member name. Otherwise, null.
The name comparison ignores case, which wasn’t necessary to hook up method handlers, but proved to be useful when wiring up properties.