Sep 9, 2009

Random nerd debates

Working as an engineer means that you get involved in random nerd debates on (at least) a weekly basis.

Most of these debates are useless drivel that aren’t worth noting but occasionally a topic comes up that is worth some level of posterity. Since my blog is otherwise full of useless stuff I figure starting a series on nerd debates isn’t the worst thing I could do :) 

So episode 1 of the Random nerd debate series.

(Interestingly you will notice that SyntaxHighlighter doesn’t even understand the Class name syntax Boolean, but does understand the alias syntax)

bool


Vs.



Boolean


Or int Vs. Int32 or whatever you want to call it. I am pretty sure I am in the minority here but I tend to prefer using the class name syntax Boolean Vs. the alias syntax bool. It is mostly personal preference but I think there are two key areas where the distinction makes a difference.



First when you are calling static methods that live on the class it seems weird to me to use the alias syntax.



bool.TryParse()


doesn’t feel the same as



Boolean.TryParse()


Again, I think I am in the minority here. My thought is that when you are calling methods you are doing so on the class itself. Using the alias just adds a level of indirection, albeit a minor and mostly overlooked one.



The second place where I think class name syntax gives you a true benefit is in clarity. When using the alias syntax int I have heard several people think that Int32 is simply a implementation detail and that the alias int hides that from you. So if you were compiling on x64 int would translate into Int64 instead of Int32.



This is a misconception however the int alias is simply that, an alias, or syntactic sugar for Int32. If you want Int64 you have to use the alias long. Of course you could specify Int64 explicitly using class name syntax and be done with it.



The more 64 bit programming becomes the norm I think the more we will run into some confusion. Do you use int, or double, or float, or long etc…



Interestingly the alias double maps to the class Double but the alias float maps to the class Single (have you ever seen someone use Single in their code?) In a chat with a friend about this topic his response was



“I go with shorter just from habit, but would generally defer to the team standard. i.e. it's not an issue I feel strongly about, but do feel that a decision one way or another needs to be made on a project”



Generally I agree with that statement and I think team level consistency is important. I think in most cases you will see teams using the alias and I think, in most case, this works out fine for them. All programmers can read the alias and I think that some may even be confused at first if they see the ClassName syntax and haven’t seen it before but, to me, it increases clarity and intent.



Stack Overflow had a nice thread about this very thing that I found while poking around for this post



You can find a complete list of all the built in type aliases for .NET, and their equivalent class name here



In a bit of a contradiction of style I do however use the var keyword very often. Which may sound like it reduces code clarity but there are places in which I purposely want to abstract the implementation details of the backing type from my code. But that debate is for episode 2. Stay tuned.

Labels: , ,

Sep 6, 2009

Grouping and Checkboxes in WPF

If you have done any with WPF radio buttons you know that WPF has given us greater flexibility to define radio groups. In WinForms radio button groups were constrained to the parent panel. This meant if you wanted radio buttons to be mutually exclusive, that is you can only have one selected at a time, they all had to live within the same parent layout panel.

In WPF you don’t have this limitation, when you specify a group name for a radio button it will be mutually exclusive to any other radio button that has the same group name within the visual tree. This gives you greater flexibility with how you layout your radio groups.

Recently, I had the need to show a popup menu within a complex layout scenario and I needed there to be only one popup open at a time. So I originally went down the route of using radio buttons. I figured I could layout radio buttons anywhere in the visual tree, give them all the same group name and then bind the IsOpen property of popup to the IsChecked property of my radio button.

This worked fine at first, however I quickly found out that once a popup was open, i.e. one of the radio buttons in the group was checked, from that point on you always had one popup open. The problem is you can’t “un-select” a radio button once it has been checked. This was not the desired behavior for my situation so I set out to find a solution that would give me mutual exclusivity and the ability to have an unchecked state for my entire group, that is nothing in the group is selected.

Enter the grouping checkboxes. What I wanted was the check / uncheck behavior of checkbox (really of the base toggle  button) with the functionality of a radio button. So I decided to do this through a simple attached property.

First I created a class called ToggleButtonExtensions. I decided to pull the functionality up to the base ToggleButton class since there is nothing in the checkbox class that I need and I wanted to give the flexibility.  This is where I am going to define my custom attached property and handle the changed event when the ToggleButton checked event fires.

So first I define my custom attached property called GroupName (I wanted the usage to feel as much like the radio button grouping as possible)

public static readonly DependencyProperty GroupNameProperty = DependencyProperty.RegisterAttached("GroupName",typeof(String),typeof(ToggleButtonExtensions),new PropertyMetadata(String.Empty, OnGroupNameChanged));


The key to hooking into the ToggleButton checked event is in the property change handler on this custom attached property. At the end of the code snippet above you see the method name OnGroupNameChanged. In that method we can get a hold of the element that is using this attached property and hook into it’s events. The body of that method looks like this:



private static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Add an entry to the group name collection
var toggleButton = d as ToggleButton;
if (toggleButton != null)
{
String newGroupName = e.NewValue.ToString();
String oldGroupName = e.OldValue.ToString();
if (String.IsNullOrEmpty(newGroupName))
{
//Removing the toggle button from grouping
RemoveCheckboxFromGrouping(toggleButton);
}
else
{
//Switching to a new group
if (newGroupName != oldGroupName)
{
if (!String.IsNullOrEmpty(oldGroupName))
{
//Remove the old group mapping
RemoveCheckboxFromGrouping(toggleButton);
}
ElementToGroupNames.Add(toggleButton, e.NewValue.ToString());
toggleButton.Checked += ToggleButtonChecked;
}
}
}
}


There are a few things going on here, first you see the last line in the method is hooking into the Checked event of the ToggleButton. This gives us a way to go through the other ToggleButtons that are a part of this group and “un-check” them. This will give us the mutual exclusivity we want.



The other thing in the method to note is how I am managing the groups of ToggleButtons. I have a simple dictionary that stores a GroupName to ToggleButton mapping. This gives me a handle to the ToggleButtons so I can uncheck them if another element in the same group gets checked.



The last thing we need to do is implement the Checked handler where we can iterate over the dictionary and uncheck any other elements in the same group as the element that is being checked. That handler method looks like this:



static void ToggleButtonChecked(object sender, RoutedEventArgs e)
{
var toggleButton = e.OriginalSource as ToggleButton;
foreach(var item in ElementToGroupNames)
{
if (item.Key != toggleButton && item.Value == GetGroupName(toggleButton))
{
item.Key.IsChecked = false;
}
}
}


And that’s it. Now we have mutually exclusive toggle buttons that allow us to have an unchecked state for the whole group.



UPDATE: Fixed Link. You can check out the sample project here.

Labels: ,