Archive for the ‘Event Handlers’ Category

WPF MVVM in VB.NET: Delegating Event Subscriptions for RoutedCommand (or any ICommand) in the ViewModel

October 21, 2009

Just started a new project in WPF. It’s my first WPF project and the firm’s first WPF project. Should be lots to blog about.

Stick One In His Eye

We are using MVVM because the WPF Pantheon (e.g. John Grossman, Josh Smith and Jason Dolinger) are in agreement that this pattern is eminently suited to WPF. So, yeah, we’re taking a bit of a Voodoo Architecture approach.

I am writing a Proof Of Concept using MVVM and found an absolutely brilliant video by Jason Dolinger here which shows a comprehensive refactoring example in MVVM while lucidly explaining the pattern. I was following the vid while coding my Proof Of Concept but got well and truly stuck on the part where Jason delegates (that’s del-e-GATEs as a verb) event subscriptions for the RoutedCommand in the ViewModel.

The Google To End All Googles

The reason I got stuck was that the vid is in C# whereas I am using VB.NET, which is not a problem in itself, but Jason was using C# Event Accessors to delegate the Event subscription. I had never heard of Event Accessors, Jason did not say what they were and VB.NET does not have them (at least not by that name).

I commenced a Google and soon saw that all the MSDN WPF examples are in C# only and not in VB.NET. I was looking for something I didn’t know the name of to do something I didn’t understand in a language which did not have the construct I needed. I was just about to wave a Dead Chicken at the monitor when, in the end Google did cough up an answer…in French. Impossible n’est pas français.

Here’s what had me stuck. What I needed was the VB.NET translation for this code

public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

First I had to figure out what the heck it was doing. Jason just said ‘now we have to wire the ICommand into the WPF Commanding system’ which left me very little the wiser. Well, ladies and gentlemen what you are witnessing above is the use of an Event Accessor to delegate (That’s del-e-GATE as a verb, not DEL-e-gate as a noun) event subscriptions.

In more detail, the ‘add’ Event Accessor is fired when an Event Subscription to CanExecuteChanged occurs. Value contains the Delegate i.e. Event Handler which is subscribing to the Event. Hence, the Event Handler denoted by value is being added to the Event Handler List for the CommandManager RequerySuggested event. This has the effect of wiring the WPF ICommand object that has that event subscription into the WPF Commanding infrastructure, thus allowing that ICommand to take effect.

VB.NET does not have Event Accessors but it does have a direct equivalent, namely Custom Events. Here’s the equivalent VB.NET code:


Public Custom Event CanExecuteChanged As EventHandler Implements System.Windows.Input.ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
'This is the AddHandler block
AddHandler CommandManager.RequerySuggested, value
End AddHandler

RemoveHandler(ByVal value As EventHandler)
'This is the RemoveHandler block
RemoveHandler CommandManager.RequerySuggested, value
End RemoveHandler
'
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
'This is the RaiseEvent block
CommandManager.InvalidateRequerySuggested()
End RaiseEvent
End Event

You can see its the same thing as a set of C# Event Accessors.

For the above code I am sobbing in helpless gratitude to binoo, moderateur of the WPF Forum at Devellopez.Com who posted the above code in this thread, entitled Modèle MVVM – Implémentation ICommand

What Are Custom Events ?

Mesdames and messuirs, you may read about Custom Events here. They enable custom handling of AddHandler, RemoveHandler and RaiseEvent calls for any event.

The above code, for example says that when AddHandler is called for a CanExecuteChanged event that the event handler for that event should be added to the RequerySuggested event of the CommandManager. The inverse happens for RemoveHandler and CommandManager.InvalidateRequerySuggested() is called when a RaiseEvent is done on a CanExecuteChanged event.

Further Reading

I will assume that anyone interested in this post knows about MVVM in WPF and why I would be wanting to wire up ICommand objects in the ViewModel, but for those who have heroically read this far without that pre-requisite knowledge, just click on the MVVM link at the start of the article and the one about the MVVM refactoring video.

And to binoo, now my favourite moderateur in the world, may your hovercraft be ever full of eels and your Brie only Triple Cream.

Advertisements

GridView Sorting Event Handler Called Twice on one OnSorting Event

March 23, 2009

This Is Not An Excuse, It’s a REASON.
It’s been three and a half years since I coded in VB.NET so while developing/maintaining a VB.NET app. on my current project I have been shamelessly copying cannily re-using a lot of existing code.

The event handlers in this app. all have “Handles” clauses hanging off them so I naively assumed this was required VB syntax. Thus began my latest journey in pain.

Something I Learned At Work Today
Did you know that when a GridView does not have a Data Source Control defined that it does not automatically Sort when you click on the Column Headers ? Of couse you did, Vikram Lahotia. I, however, did not as all my Grids had nice ObjectDataSources or similar.

THIS particular one, however, is bound to a DataTable stored in ViewState (N.B. I did not write this page) , so after I found out why it didn’t Sort automatically, I had to handle the OnSorting event, which I did as you might expect:

asp:GridView ID="TrevTheGridView runat="server" etc
OnSorting="TrevTheGridView_OnSorting
Fields and stuff
/asp:GridView

In addition, due to my VB.NET naivety I also did this in code-behind:

Protected Sub TrevTheGridView_Sorting(ByVal sender as Object, ByVal e as GridViewSortingArgs) Handles trevTheGridView.Sorting
‘Flip The Sort Order
‘Define a DataView on the ViewState datatable
‘Assign SortExpression to DataView
‘Rebind Trev to the DataView.ToTable
End Sub

Notice that Handles clause? It’s redundant. I repeat: It’s redundant. The combination of the Handles gridView.Sorting in code-behind and OnSorting=”sortEventHandler” in Markup meant that the Sorting event handler was called twice which caused my Sort Order to be flipped twice meaning that the GridView Sort Order never changed.

Tremendous. If I want to watch something never change I’ll go live in Delaware or hook up to Richie Benaud’s hairdresser on WebCam.

So get rid of the Handles clause if you only want the event handler firing once. Or the declaration if the Event Handler in Markup.

When Are Custom Event Handlers Attached ?

November 18, 2008

I have a UserControl inside a GridView.
When are the Custom Event Handlers attached to the UserControl ?
Please tell me because I have no idea.

In the scenario below the UserCreated event handler is null at the time the UserCreated event is fired, i.e. during DataBinding. Once the page has fully loaded the event handlers are available.

UserControl

public event EventHandler UserCreated;
public event EventHandler UserSelected;

///
/// Bubble up the UserCreated event
///
protected virtual void OnUserCreated(object sender, UserCreatedArgs e)
{
EventHandler handler = UserCreated;
/*
UserCreated above is null during databinding. No handler is present
A handler is present after page has fully loaded i.e. UserCreated != null
*/

if (handler != null)
{
handler(this, e);
}
}

///
/// Raise the OnDataBindingEvent
///
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
InitialiseControl();
}

///
/// Initialises the data in the UserControl.
///
private void InitialiseControl()
{
List userList =
UserController.GenerateUserNameDropDownList(UserGroupName);
OnUserCreated(userList);
}

Page On Which UserControl is Hosted

///
/// Handles the Load event of the Page control.
///
protected void Page_Load(object sender, EventArgs e)
{
UserCreatedHandler += UserControl.UserCreated
}

protected void UserCreatedHandler(object sender, UserControl.UserCreatedArgs e)
{
...handle userCreated event
}

Markup For The Page

asp:GridView ID="keyPersonnelGridView" runat="server"
Columns
asp:TemplateField
ItemTemplate
userControl:UserName ID="personnelList" runat="server" UserGroupName="All Users"
/ItemTemplate
/asp:TemplateField
..rest of tags closed
/asp:GridView

Can any kind soul please explain why my Event handlers are not present when the event is fired ?

Muchos Gracias Tadpolaramus