Mad Props!

Omniscience is just a Google-search away.

Login

You're reading Mabsterama, the weblog of Matt Hamilton. Enjoy your stay.

Enter-to-Tab in WPF

Like many users of line-of-business applications, my own users just can't understand the Tab key. For them, pressing Enter on the keyboard shouldn't submit a form, it should just move their focus to the next control.

Back in the Windows Forms days there was a neat way to achieve this functionality: You caught the KeyDown event on each of your controls and used the SelectNextControl method to move focus to the next control. In WPF, however, there's no SelectNextControl method! So how do we do something similar?

The first trick to use in WPF is to handle the PreviewKeyDown event on all your data-entry controls in one hit, rather than having to declaratively handle it individually in each control. In my case I have all my controls inside a grid, so I simply declare my grid like this:

<Grid UIElement.PreviewKeyDown="Grid_PreviewKeyDown">

What I'm doing here is telling the grid that any child control that descends from UIElement (and that includes TextBoxes and ComboBoxes) should have their PreviewKeyDown event handled by a common method called Grid_PreviewKeyDown.

So now we have caught key presses on our controls. Now, how do we tell the window to move its focus to the next available control? We don't have SelectNextControl, but we have a new method with a similar function: MoveFocus!

private void Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
var uie = e.OriginalSource as UIElement;

if (e.Key == Key.Enter)
{
e.Handled = true;
uie.MoveFocus(
new TraversalRequest(
FocusNavigationDirection.Next));
}
}

So here we're getting the control that sent us the PreviewKeyDown event, and calling its MoveFocus method to shift the focus to the next control!

So now you have no excuses! WPF can be used for line-of-business style applications after all!

100011

Today I turn 35! Fate was kind enough to schedule a four-day weekend around my birthday so it's like an extended birthday celebration for me this year. People really seem to be embracing the concept - they're giving each other chocolate eggs in my honour etc. Couldn't be happier.

My birthday haul this year has included an awesome statuette of Altair from Assassin's Creed, a copy of Family Guy: Blue Harvest and Office Space on DVD and the latest CD from The Panics.

So remember the true meaning of this 2008 long weekend: My thirty-fifth!

Back to Basics - Reading a .CSV File

I knocked up a very quick program yesterday to read in a .CSV file and present it to the user in a DataGridView for editing (and eventually saving to a database). While discussing the code with Andrew this morning, he suggested a post in the same vain as Carl Franklin's "Better Know a Framework" from .NET Rocks to go over some of the things the code does, so here it is.

The first trick in my code is to read the entire .CSV file into an array of strings. Nothing fancy required, here - I make use of the built-in File.ReadAllLines method:

var content = File.ReadAllLines(fileName);

Now I have a variable called "content" - an array of strings.

Next I want to loop through those lines, splitting them into the individual comma-separated fields. I start my iterator at 1 so it skips the column header row:

for (int i = 1; i < content.Length; i++)
{
var line = content[ i ];

In the file I'm reading, I know that there's nothing tricky going on like embedded commas wrapped in double-quotes, so I can just using the string.Split method, like this:

 var fields = line.Split(new char[] { ',' });
if (fields.Length != 6) continue;

My very simple error checking here is just making sure that there are six fields on the line (in case the .CSV file is corrupt in some way). I use the continue keyword to jump back up to the next "for" iteration if something's wrong with that line.

Next I want to parse a few of the fields and populate a custom object with their values. My object in this case is called "KillRecord" (this is a CSV with meat pH readings from carcases). I start by parsing the date using DateTime's TryParseExact method, which lets me specify the exact format I expect the date to be in:

 DateTime date;
if (!DateTime.TryParseExact(
fields[1], "dd/MM/yy",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out date)) continue;

Again I simply continue to the next line if something's wrong - no real error reporting in this utility.

Next I want to parse the pH value, a float:

 float pH;
if (!float.TryParse(fields[4], out pH)) continue;

Pretty straight forward.

Lastly I construct my KillRecord object and add it to a predefined list (a BindingList<KillRecord> that the form's DataGridView is bound to):

 var rec = new KillRecord(date, pH);
records.Add(rec);
}
So that's my code to read in a .CSV file. Like I said: Nothing fancy. I just wanted to break down some of the things I'm doing for those who might be new to .NET. Adding proper error handling and reporting is left as an exercise to the reader! ;-)

Imposing Interfaces onto Classes with Extension Methods

Before you get excited, this post is just about floating an idea rather than explaining how to do something, but bear with me and see if you think it'd be handy.

Imagine you're given a class library with a Customer class in it. You want to make a nice little modal edit form so your user can edit a Customer, and the form should have an OK and Cancel button.

You put together your form, and it looks sweet. So then you start typing the code to bring up the form:

Customer cust = GetCustomer();
CustomerForm custForm = new CustomerForm(cust);
cust.BeginEdit();
if (custForm.ShowDialog() == DialogResult.OK)
{
cust.EndEdit();
}
else
{
cust.CancelEdit();
}

Looks great, huh? Except ... you compile, and you realise that the creator of the Customer class never bothered to implement the IEditableObject interface.

So now you have to write your own little helper methods to save off the properties of your Customer, and put them back when the user clicks Cancel. Ugh.

Wouldn't it be nice if you could "impose" an interface onto a class, and tell the compiler what to call when the interface methods/properties are called? So in the example above you could define the IEditableObject methods (BeginEdit, EndEdit and CancelEdit) for Customer, and tell the compiler that Customer does indeed implement IEditableObject - and to use those methods for its implementation.

I have no idea what the syntax might look like. Some take on the "this" keyword you use to define an extension method, I suppose. Perhaps something like this:

public static class CustomerStuff
{
public static void IEditableObject.BeginEdit(this Customer cust)
{
// save away the customer
}


public static void IEditableObject.CancelEdit(this Customer cust)
{
// roll the customer back
}
}

The compiler, of course, would have to complain if you didn't implement the entire interface (notice I've forgotten EndEdit in the example above).

Maybe my IEditableObject example is a bit weak, but imagine if you wanted to define your own implementation of IComparable<T> for a class that you didn't own. Or ISerializable! Would that be worth something to you?

Bil Simser is my Canadian Doppelgänger

So Bil Simser made a comment in a recent post on his blog that he used to work on a project called Harbour. Harbour was an open-source attempt to write a CA Clipper compiler, and had a bit of a cult following amongst a dedicated group of Clipperheads. Now, if you look at the list of people who worked on the project, you'll see a familiar name at the top.

I've been subscribed to Bil's blog for years and never made the connection, so I had to leave him a comment about Harbour.

A few email exchanges later, and now I learn that Bil, too, has a personal project that's comic-book-related!

So: .NET developer ... former Clipperhead/Harbour crew member ... comic-book enthusiast.

Bil Simser is my doppelgänger! He's the Canadian mabster! You heard it here first!

Compact Framework or Silverlight?

Shawn Wildermuth posted overnight about a news story that Microsoft is working with Nokia to get Silverlight working on Symbian phones.

He also links to an article that mentions Silverlight getting a Windows Mobile port.

Now, when Silverlight 1.1 (now 2.0) was first announced as having a subset of the .NET Framework built in, I speculated that this may be the future for mobile development. That one day we may see the .NET Compact Framework disappear in favour of Silverlight. Could this be the start of that? I really hope so.

Code Camp Oz Live Twittering

If you're headed to Code Camp Oz this year, Andrew has come up with a novel idea.

Using Hashtags, we can have attendees live-twittering (tweeting?) the event.

All you need to do is follow @hashtags on Twitter, and then include the word "#ccoz" in your tweet. Then you can subscribe to the #ccoz RSS feed to see tweets from the event. Or you can view the tracking page for the #ccoz tag.

What would be awesome is if the code camp organizers could arrange a dedicated screen to show the live tweets (a la MIX08's Flotzam), but somehow I don't think their budget quite stretches that far!

Anyway, looking forward to the event!

Is MS Solving ORM from the Wrong End?

On my drive home this afternoon I listened to episode 102 of Hanselminutes, where Scott talks to Mike Pizzo from the ADO.NET Entity Framework team.

Mike's description of the EF was great - it was a much better show than the recent .NET Rocks! episode on the same topic. Something that Mike said, however, really caught my attention. He talked about the impedance mismatch between the way we code our objects and the way relational databases store data. The fact that relational databases just have tables and constraints, and don't have concepts for relationships, inheritance etc.

It's an old problem, and one that countless ORM (object-relational mapping) products have tried to solve over the years. The Entity Framework is just the latest in a long string of attempts from Microsoft to make object-oriented coding against a relational database easier.

But is Microsoft attacking the problem from the wrong end?

Is there a reason that SQL Server, or (better still) a new database product from Microsoft, couldn't introduce concepts like relationships and inheritance? I mean, I know that such concepts aren't supported by standard SQL ... but is that a big deal? Unless I'm writing a product that can support multiple database back-ends, do I really care if the access method for the database is standard SQL?

What if Microsoft were to bring out a product whose only means of access, rather than SQL, was via the CLR? A database with object-oriented properties like inheritance and relationships, but also relational features we've come to depend on like indexes and constraints? Wouldn't that be worth something to all us .NET developers?

I know there are object-based and hierarchical databases out there, but really Microsoft is in the unique position of being able to bring such an animal into the mainstream, with full .NET support. Is it too much to ask?

Geek Dinner Postponed

I doubt I'll catch anyone in time if they're planning on going tonight, but our geek dinner has been postponed 'til next Tuesday. Still at the Boomerang Motel, still at 7pm.

Hope to see you there!

Generic Extension Methods Example

Ayende has posted about generic extension methods, in particular his surprise that they work at all. In the same vein, I thought I'd post some code that we're using in production here at work.

Pete had to assign a bunch of data to a set of rows in a DataTable, but didn't want to change anything if the values were the same. Rather than writing lines and lines of comparisons and assignments, we made ourselves an extension method on DataRow that only overwrites the field's value if it's DbNull or different to the value we've given it.

As a bonus, these extension methods support nullable types, so if you pass in a Nullable<int> then we can test for null and assign DbNull to the field. Also note there's a special one at the top just for string, since we want to trim the string before comparing (in the case of plain old char fields).

public static void SmartAssign(this DataRow row,
    string columnName, string value)
{
if (row == null) throw new ArgumentNullException("row");
int columnIndex = row.Table.Columns.IndexOf(columnName);
if (value == null)
{
row[columnIndex] = DBNull.Value;
return;
}
value = value.Trim();
if (row.IsNull(columnIndex))
{
row[columnIndex] = value;
return;
}
string currentValue = row[columnIndex].ToString().Trim();
if (value != currentValue)
{
row[columnIndex] = value;
}
}
public static void SmartAssign<T>(this DataRow row,
string columnName, T value)
{
if (row == null) throw new ArgumentNullException("row");
int columnIndex = row.Table.Columns.IndexOf(columnName);
if (value == null)
{
row[columnIndex] = DBNull.Value;
return;
}
if (row.IsNull(columnIndex))
{
row[columnIndex] = value;
return;
}
if (!value.Equals(row[columnIndex]))
{
row[columnIndex] = value;
}
}
public static void SmartAssign<T>(this DataRow row,
string columnName, Nullable<T> value) where T : struct
{
if (row == null) throw new ArgumentNullException("row");
int columnIndex = row.Table.Columns.IndexOf(columnName);
if (!value.HasValue)
{
row[columnIndex] = DBNull.Value;
return;
}
if (row.IsNull(columnIndex))
{
row[columnIndex] = value.Value;
return;
}
if (!value.Equals(row[columnIndex]))
{
row[columnIndex] = value.Value;
}
}