Archive for February 2009

Verify your property names in INotifyPropertyChanged implementation

Update: I have posted another article here that explains what I think is a better solution to this problem using a simple PostSharp attribute.

When you raise the PropertyChanged event you have to pass it a property name as a string. If there is no property with that name then nothing will happen. The listener will not be notified and no exception will be thrown making the problem very difficult to debug. You can change this behaviour and make the application fail at runtime by adding a simple check to your helper function for the event:

Public Sub NotifyPropertyChanged(ByVal propertyName As String)
    ' Throw an exception if the property doesn't exist
    If Me.GetType().GetProperty(propertyName) Is Nothing Then
        Throw New InvalidPropertyNameException()
    End If
 
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub

If you put this in a base class for all of your model views (or controllers, or presenters) then you will automatically get this functionality every time, preventing some potentially very annoying bugs.

This still isn’t the ultimate solution because you don’t find out that the property name doesn’t exist until runtime. Ideally, we would get a compile error when the property does not exist. What I would like to do is call the function like this:

NotifyPropertyChanged(AddressOf MyProperty)

This way you wouldn’t have to use a string at all and the compiler would tell you if MyProperty doesn’t exist. Unfortunately, .NET languages only have delegates for functions/subroutines so there is no way to make a strongly typed pointer to a property. Let’s hope they add that in one day, but until then, we’ll have to use strings.

Nullable combo boxes in WPF

Update: Sample source code demonstrating this technique can be downloaded here: WpfNullableComboBox.zip

By default, combo boxes in WPF have some really annoying behaviour. When the control is initialized, if the SelectedItem is Nothing then the default selection will be blank, but as soon as you choose an item in the combo box, you can not reselect the blank/null option. One quick way around this is to add a null placeholder object to your ItemsSource. There are a few problems with this approach though:

  1. The null placeholder cannot actually be Nothing/null or else selecting the value will have no affect. Instead, it needs to be some object that represents “null”. This means that if you want your setter on the property bound to the SelectedItem to be set to null, you need to convert the object representing null to actually be Nothing/null.
  2. Ideally, you should not have to alter the collection in your model view/controller/presenter that is bound to the ItemsSource just to add a null option. It would be better if we could just specify in XAML that this combo box should have a null option that actually sets the SelectedItem to Nothing.

Since we don’t want to alter the collection in the controller and we cannot have a combo box item of Nothing (we need a null place holder object instead) but we don’t want the SelectedItem property to ever have the null place holder object as its value (we want it to just be Nothing when that is chosen) we can do one of two things:

  1. Use two converters: one on the ItemsSource to add in the null place holder object and one on SelectedItem to convert the place holder to Nothing.
  2. Create a user control that acts as a wrapper around the combo box control. All the necessary logic could be handled within the user control.

Option one would look like this:

<ComboBox
    ItemsSource="{Binding MyItems, Converter={StaticResource addNullPlaceHolderConverter}}"
    SelectedItem="{Binding MySelectedItem, Converter={StaticResource placeHolderToNullConverter}}" />

In my opinion, that method really sucks. You have to add the converters in you resources section and then specify them in two places. Another issue is that we could run into some major converter explosion if it turns out that you already need some other converter on one of the properties. Then you have to make a new converter that combines the two. I don’t like it.

Option two looks like this:

<local:NullableComboBox
    ItemsSource="{Binding MyItems}"
    SelectedItem="{Binding MySelectedItem}" />

Much better!

The XAML for the user control is extremely simple. You just need to create a combo box with a name:

<UserControl x:Class="NullableComboBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ComboBox x:Name="combo" />
</UserControl>

In the code-behind you need to expose two dependency properties: SelectedItem and ItemsSource so that the control has the same interface as a regular combo box.

By listening to the combo box’s SelectionChanged event you can update the SelectedItem property on the NullableComboBox except with the place holder converted to Nothing.

Brutal loading times deleting files in Visual Studio

I have long had an issue with Visual Studio where it takes a ridiculous amount of time to delete a file. Sometimes it takes over a minute and the IDE is completely unusable while it is loading. I finally came across a this post by Matt Hinze that gives a solution. Apparently when you delete a file it scans your recycle bin which can take a long time if there are lot of files in there. All you have to do is empty your recycle bin and you should be able to delete files with no noticeable delay.

Forcing form validation in WPF before user input

By default, validation is not enforced on a binding until after the value has been changed once. Consider this situation: A form has a text box whose contents should not be empty, but its starting value is the empty string. The text box will not show an error when the form is loaded. Instead, it will only show its error style after the user types in some text and then deletes it. Some people would call this a feature, but I prefer to have the validation checked right away so that I immediately know what the required fields are, and which starting values are invalid.

A quick hack

One way to tackle this is to hook a loaded event to the control and then call UpdateSource() from code:

Private Sub myTextBox_Loaded(ByVal sender As System.Object, _
        ByVal e As System.Windows.RoutedEventArgs) Handles myTextBox.Loaded
 
    BindingOperations.GetBindingExpression(myTextBox, _
        TextBox.TextProperty).UpdateSource()
 
End Sub

Unfortunately, this really isn’t a desirable solution because it requires some pretty ugly code-behind (not that there’s any other kind) and needs to be done over again for every binding. What we really want is for this functionality to be a part of the binding markup extension.

Creating a wrapper around the binding markup extension

At first I thought it would be easy to just inherit from the Binding class and override ProvideValue, but of course, it is marked as NotOverridable (sealed in C#). Instead, I create a class called ValidationBinding that inherits directly from MarkupExtension and has the new class manage an instance of Binding. The code looks like this:

Imports System.Windows.Markup
 
Public Class ValidationBinding
    Inherits MarkupExtension
 
    Private _binding As New Binding
    Private _dependencyObject As DependencyObject
    Private _dependencyProperty As DependencyProperty
 
    Public Sub New()
        _binding.ValidatesOnDataErrors = True
        _binding.ValidatesOnExceptions = True
    End Sub
 
    Public Sub New(ByVal path As String)
        Me.New()
        _binding.Path = New PropertyPath(path)
    End Sub
 
    Public Overrides Function ProvideValue _
        (ByVal serviceProvider As System.IServiceProvider) As Object
 
        Dim valueTarget = _
            DirectCast(serviceProvider.GetService(GetType(IProvideValueTarget)),  _
            IProvideValueTarget)
 
        _dependencyObject = valueTarget.TargetObject
        _dependencyProperty = valueTarget.TargetProperty
 
        If TypeOf _dependencyObject Is FrameworkElement Then
            Dim element = DirectCast(_dependencyObject, FrameworkElement)
            If element.IsLoaded Then
                ForceValidation()
            Else
                AddHandler element.Loaded, AddressOf ElementLoaded
            End If
        Else
            ForceValidation()
        End If
 
        Return _binding.ProvideValue(serviceProvider)
 
    End Function
 
    Private Sub ForceValidation()
        BindingOperations.GetBindingExpression(_dependencyObject, _
                                               _dependencyProperty).UpdateSource()
    End Sub
 
    Private Sub ElementLoaded(ByVal sender As System.Object, _
                              ByVal e As System.Windows.RoutedEventArgs)
        ForceValidation()
    End Sub
 
    Public Property Path() As PropertyPath
        Get
            Return _binding.Path
        End Get
        Set(ByVal value As PropertyPath)
            _binding.Path = value
        End Set
    End Property
 
    ... the rest of the binding properties go here
 
End Class

The binding can then be used like this (where my is an imported namespace containing ValidationBinding):

<TextBox Margin="5" Text="{my:ValidationBinding Path=Text}" />

As an example, I have exposed the Binding’s Path property, but you actually have to do this for all of the public properties in Binding. A reference of all the properties that should be implemented can be found here.

ProvideValue returns the result of the Binding’s ProvideValue function, but first it checks whether the binding target has finished loading. If it has already finished loading then it forces validation by calling UpdateSource() on the target. In the much more likely scenario that the control has not yet loaded (this will be the case when you set your binding in XAML) it attaches a handler to the Loaded event so that the ForceValidation subroutine can be deferred until it is finished loading.

Also, notice that I set both ValidatesOnDataErrors and ValidatesOnExceptions to True in the constructor so that I didn’t need to specify it in the XAML. Chances are that whenever you use this markup extension you will want those enabled anyways.

It may seem like a lot of work, but it is a very reusable solution that gives you significantly more power.

Manipulating automatically generated LINQ to SQL classes

There are a few problems with the data model code that is automatically generated in LINQ to SQL. The most obvious issues are that class names are not capitalized and that tables with two foreign keys to the same table will not have descriptive names. For example, if a table has columns firstUserID and secondUserID which are both foreign keys to the users table then you would probably hope to see the properties FirstUser and SecondUser on that class. Unfortunately, what you will actually get is User and User1 which is pretty much pointless because it is very difficult to tell which one is which. One way to tackle this is to simply change the code after it has been generated so that it looks like you want it to. But then as soon as you change the database and import the model again your changes are lost and have to be redone every time. Ideally, the automatically generated code would be formatted exactly as you want it.

The solution I came up with was to useĀ SqlMetal to generate XML output, then manipulate that output and feed it back into SqlMetal so that it can generate the code from the altered XML. As a naming heuristic, I specified that a foreign key column’s property would have a name derived from the column name without the “ID” suffix and a capitalized first letter. Depending on the extent of the changes you plan on making, you may want to make an XSLT file to translate the XML, or simply use some regular expressions.

One downside to this approach is that SqlMetal often cannot generate code for stored procedures because it is unable to determine the return type without actually running the procedure. To get around this I told SqlMetal not to generate any code for the stored procedures (just omit the /sprocs argument), then manually incorporated the XML for my stored procedures in the XSLT file so that it would be injected into the second input to SqlMetal that actually generates the code.

Discard changes in LINQ to SQL DataContext

The LINQ to SQL DataContext provides excellent functionality for managing a set of local changes to a database that can be pushed to the server with a single call to SubmitChanges(). Inevitably there will be situations where you want to discard the changes you have made, effectively allowing you to continue using the DataContext as though those changes had never been made. Unfortunately, there is no DataContext.DiscardChanges() method.

A little research reveals that this is by design and that you should simply recreate the DataContext in these cases, but of course, nothing is that simple. Every object you have that came from the original DataContext now needs to be reset to use the new one to guarantee predictable behaviour. For example, the last line of this snippet will set objectsAreEqual to False:

' Create two data contexts
Dim dc1 As New UsersDataContext
Dim dc2 As New UsersDataContext
 
' Grab the same record out of both the data contexts
Dim user1 = dc1.Users.First
Dim user2 = dc2.Users.First
 
' False, because the otherwise identical records come from different contexts
Dim objectsAreEqual = user1 = user2

Basically, this shows that it does matter where your object came from. If you just want to discard a few little changes and you don’t want to have to recreate all your variables, you can instead undo all the changes that you have made so far and continue to use the same DataContext.

Undoing inserts and deletes is easy, because we can just do the opposite to revert the change. Luckily there is even a nice function on the DataContext that will show us what we need to do called GetChangeSet:

Public Sub DiscardInsertsAndDeletes(ByVal data As DataContext)
    ' Get the changes
    Dim changes = data.GetChangeSet()
 
    ' Delete the insertions
    For Each insertion In changes.Inserts
        data.GetTable(insertion.GetType).DeleteOnSubmit(insertion)
    Next
 
    ' Insert the deletions
    For Each deletion In changes.Deletes
        data.GetTable(deletion.GetType).InsertOnSubmit(deletion)
    Next
End Sub

LINQ to SQL is smart enough to know that if a row is inserted and then deleted (or the other way around) nothing needs to be done. If you look at the ChangeSet after running this function, you will notice that the Inserts and Deletes collections are empty. Updates are a little more annoying. If you update a value, and then set it back to its original state then you will get the expected behaviour (ie: the ChangeSet will be empty because you reverted your change) but unless you write code to keep track of the original value yourself, there is no way to automatically put an object back into its start state without hitting the database. If hitting the database is acceptable, you can always use the Refresh function to get rid of the updates:

Public Sub DiscardUpdates(ByVal data As DataContext)
    ' Get the changes
    Dim changes = data.GetChangeSet()
 
    ' Refresh the tables with updates
    Dim updatedTables As New List(Of ITable)
    For Each update In changes.Updates
        Dim tbl = data.GetTable(update.GetType)
        ' Make sure not to refresh the same table twice
        If updatedTables.Contains(tbl) Then
            Continue For
        Else
            updatedTables.Add(tbl)
            data.Refresh(RefreshMode.OverwriteCurrentValues, tbl)
        End If
    Next
End Sub