Archive for the ‘WPF’ Category.

WPF Responsiveness: Asynchronous Loading Animations During Rendering

Download the code here: WpfLoadingOverlay.zip

A common issue in MDI or TDI style user interfaces is that it can take a long time to render new forms when they are opened. Even a one or two second delay is enough to make an application seem very unresponsive. If there’s nothing you can do to improve the actual performance (ie: the total time to load the form) you can at least improve the perceived performance. This code sample creates a simple form with a tab control and a button. Every time you click the button it adds a new tab with 4000 text boxes. Depending on the speed of your computer the form will probably take around five seconds to load. As soon as you click the button, the new tab appears with a loading animation that continues until the contents have been rendered. This is not a trivial task because we want to render a loading animation at the same time that we are waiting for another long rendering operation to complete. Basically, we need two rendering threads. You can’t have multiple rendering threads in a single window, but you can put your loading animation in a new window with its own rendering thread and make it look like it’s not a separate window.

The loading overlay is a separate, chromeless window that does not appear on the taskbar and disappears as soon as loading is complete. The window is also semi-transparent and automatically positioned exactly over top of the form that is loading, so it looks like it is a part of the existing window.

Download the sample project and try it out.

Finding all validation errors on an IDataErrorInfo object

WPF data binding has built in support for IDataErrorInfo, so it is easy to display a validation error when a property has invalid data. However, sometimes we need to manually find all the validation errors on an object. A perfect example of this is when trying to save data. Often you will want to verify that there are no validation errors before allowing the save operation to proceed. Using the MVVM pattern it would be ideal to determine whether there are any errors purely within your model view. The default behavior of IDataErrorInfo does not give a collection of all current errors. Instead, it will just tell you if a given property has an error (ie: using IDataErrorInfo.Item), so all we have to do to find all the errors is enumerate through each property on the class and call the Item property with that property name as the argument. The GetValidationErrors function below does exactly that:

Option Strict On
 
Imports System.ComponentModel
 
Public Class ValidationHelper
 
    ''' <summary>
    ''' Checks for errors in <c>validatable</c> and returns all the errors found.
    ''' </summary>
    Public Shared Function GetValidationErrors(ByVal validatable As IDataErrorInfo) As IEnumerable(Of DataError)
 
        Dim errors As New List(Of DataError)
 
        ' Iterate through every property in the class
        For Each prop In validatable.GetType.GetProperties
 
            ' If the property has an error, then add it to the list
            Dim errorMessage = validatable(prop.Name)
            If errorMessage IsNot Nothing Then
                errors.Add(New DataError(prop.Name, errorMessage))
            End If
 
        Next
 
        Return errors
 
    End Function
 
    ''' <summary>
    ''' Represents a single error.  It's a propertyName, errorMessage pair
    ''' </summary>
    Public Class DataError
 
        Private _propertyName As String
        Private _errorMessage As String
 
        Public Sub New(ByVal propertyName As String, ByVal errorMessage As String)
            _propertyName = propertyName
            _errorMessage = errorMessage
        End Sub
 
        ''' <summary>
        ''' The name of the property that has the error.
        ''' </summary>
        Public ReadOnly Property PropertyName() As String
            Get
                Return _propertyName
            End Get
        End Property
 
        ''' <summary>
        ''' A description of the property's error.
        ''' </summary>
        Public ReadOnly Property ErrorMessage() As String
            Get
                Return _errorMessage
            End Get
        End Property
 
    End Class
 
End Class

Specifying expected DataContext type in WPF

Josh Smith just made a blog post about XAML DataContext comments when using the MVVM pattern. He makes a great point, which is that in many cases it is not immediately obvious what the DataContext of a view is intended to be. A simple comment as Josh suggests will go a long way, but the downside is that comments create a maintainability issue. If you rename a model view, or refactor code so that a page, window or user control expects a different DataContext you also need to update the comment. Here’s an example:

<!-- DataContext = SampleModelView -->
<UserControl x:Class="SampleUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300">
    <Grid>
 
    </Grid>
</UserControl>

But now what if I change my mind and decide that instead of SampleModelView, this UserControl will have AlternateModelView as its DataContext? If I forget to update the comment then it is now a source of misinformation. What I would really like to do is somehow specify the expected data context type for a given UI element, so I created an attached property called ExpectedDataContextType. When the element is loaded, it will fail at runtime if the DataContext is not of the desired type. It looks like this:

<UserControl x:Class="TestControl"
    xmlns:local="clr-namespace:ExpectedDataContextType"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300"
    local:DataContextHelper.ExpectedDataContextType="{x:Type local:TestModelView}">
    <Grid>
        <TextBlock>Hello</TextBlock>
    </Grid>
</UserControl>

The code is extremely simple. It just attaches a handler to the Loaded event and then checks the type. When the types do not match up it gives you a warning via a message box if you are debugging. I chose not to throw an exception because the exception gets covered up and just ends up as a tiny message on Visual Studio immediate window. When I am debugging and a control has the wrong DataContext I want to make sure I find out about it, hence the message box. You can always replace the message box code with something else though.

Option Strict On
 
Public Class DataContextHelper
 
    Public Shared Function GetExpectedDataContextType(ByVal element As DependencyObject) As Type
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        Return DirectCast(element.GetValue(ExpectedDataContextTypeProperty), Type)
    End Function
 
    Public Shared Sub SetExpectedDataContextType(ByVal element As DependencyObject, ByVal value As Type)
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        element.SetValue(ExpectedDataContextTypeProperty, value)
    End Sub
 
    Public Shared ReadOnly ExpectedDataContextTypeProperty As  _
                           DependencyProperty = DependencyProperty.RegisterAttached("ExpectedDataContextType", _
                           GetType(Type), GetType(DataContextHelper), _
                           New FrameworkPropertyMetadata(Nothing, AddressOf OnExpectedDataContextTypeChanged))
 
    Private Shared Sub OnExpectedDataContextTypeChanged(ByVal obj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
        Dim element = DirectCast(obj, FrameworkElement)
        AddHandler element.Loaded, AddressOf OnElementLoaded
    End Sub
 
    Private Shared Sub OnElementLoaded(ByVal sender As Object, ByVal args As RoutedEventArgs)
        Dim element = DirectCast(sender, FrameworkElement)
 
        RemoveHandler element.Loaded, AddressOf OnElementLoaded
 
        ' Compare the expected type to the actual type
        Dim expectedDataContextType = GetExpectedDataContextType(element)
        Dim actualDataContextType = element.DataContext.GetType
        If expectedDataContextType IsNot actualDataContextType Then
 
#If DEBUG Then
            ' The types don't match and debug mode is on so notify the developer that the element
            ' has the wrong data context
            MessageBox.Show(String.Format("DataContext has type {0}. Expected {1}.", _
                                          actualDataContextType.ToString, _
                                          expectedDataContextType.ToString))
#End If
 
        End If
    End Sub
 
End Class

The end result is that you are still specifying what the type of your DataContext should be, but now it is actually enforced. The best part is that if the you rename your model view without updating the ExpectedDataContextType property you will get a compile error because the type no longer exists. If the type still exists then you have to settle for a runtime error.

WPF super converters are bad for unit testing

I recently learned about a WPF converter library on CodePlex. They are all very flexible and it is pretty amazing what you can do with just a few converters. Here’s a sample usage of one of the converters from the project’s documentation:

<MultiBinding>
	<MultiBinding.Converter>
		<con:ExpressionConverterExtension>
			<con:ExpressionConverterExtension.Expression>
				<![CDATA[
				{0} && {1} && {3} && !{2}
				]]>
			</con:ExpressionConverterExtension.Expression>
		</con:ExpressionConverterExtension>
	</MultiBinding.Converter>
</MultiBinding>

This MultiConverter returns true if parameters 0, 1 and 3 are true and parameter 2 is false. At first this looks pretty awesome, but I think it is a little dangerous for any team trying to maximize their test coverage. As soon as you start putting relatively complex logic right into your XAML you are basically writing code that cannot be tested. One of the fundamental principles of MVVM is that your view should be simple. If this {0} && {1} && {3} && !{2} logic is moved to a regular converter, or better yet (maybe) into a ModelView it becomes testable code.

MultiBindings are NOT useless in MVVM

Lately I have been detecting a growing sentiment that any use of MultiBinding is poor practice in MVVM (this thread on WPF disciples for example). However, I think people who say you should never use MultiBinding are missing its point. It is probably better to make a single binding to a FullName property than to multi bind to FirstName and LastName and then convert it into a full name. But there is still a scenario that demands the use of MultiBinding: bindings that need to update when more than one UI property changes. MultiBindings are not just used for passing more information to the converter, they also specify when the value needs to be updated and call the converter again. This is a much more important feature and it requires MultiBinding.

WPF nullable combo box source code

Download the code here: WpfNullableComboBox.zip

A few months ago I wrote this article on making a nullable combo box control in WPF. I had a bunch of requests to see an actual implementation, so here is a sample Visual Studio 2008 project with the source code for the user control. It basically uses the same technique I described in my previous blog post. All the combo box properties (even the obscure ones no one will ever use) are implemented.

Easier PropertyChanged notification with PostSharp

As I described in this previous article raising the PropertyChanged event for classes that implement INotifyPropertyChanged can be a real pain. The biggest problem is that PropertyChangedEventArgs takes the name of the property that changed as a string and as we all know, strings are the root of all evil. Here I will show how to use a simple PostSharp attribute on your properties that need to raise the PropertyChanged event when they are changed so that you don’t manually need to do it and hard code the name of the property as a string. PostSharp is a framework for .NET that allows for aspect oriented programming. You can read all about it at the PostSharp website.

First of all, let’s assume that the classes implementing INotifyPropertyChanged are model view classes in the MVVM pattern. We will use a base class for all model views called BaseModelView that looks like this:

Imports System.ComponentModel
 
''' <summary>
''' Parent class for all model views
''' </summary>
Public Class BaseModelView
    Implements INotifyPropertyChanged
 
    Public Event PropertyChanged( _
        ByVal sender As Object, _
        ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
        Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
 
    ''' <summary>
    ''' Raises the <c>PropertyChanged</c> event for the property with the given name.
    ''' </summary>
    ''' <param name="propertyName">The name of the property that has changed.</param>
    ''' <remarks>If there is no property on this class with the given name, then an
    ''' exception will be thrown.</remarks>
    Public Sub OnPropertyChanged(ByVal propertyName As String)
 
        ' Throw an exception if the property doesn't exist
        If Me.GetType().GetProperty(propertyName) Is Nothing Then
            Throw New ArgumentException( _
                String.Format("The property {0} doesn't exist on type {1}.", _
                              propertyName, _
                              Me.GetType().Name))
        End If
 
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
 
    End Sub
 
End Class

This class is very important. There needs to be a method for property change notification (ie: OnPropertyChanged on BaseModelView) instead of just an event (ie: PropertyChanged on INotifyPropertyChanged) because the attribute cannot directly raise an event, but it can call a public method that raises the event. The PostSharp attribute looks like this:

Imports PostSharp.Laos
Imports System.ComponentModel
 
<Serializable()> _
Public Class NotifyAttribute
    Inherits OnMethodBoundaryAspect
 
    Public Overrides Sub OnExit(ByVal eventArgs As PostSharp.Laos.MethodExecutionEventArgs)
        ' Convert to BaseModelView
        Dim notifier = TryCast(eventArgs.Instance, BaseModelView)
 
        ' If the instance is the wrong type then throw an exception
        If notifier Is Nothing Then
            Throw New InvalidOperationException("Cannot raise PropertyChanged event unless instance implements INotifyPropertyChanged.")
        End If
 
        ' Ignore everything that's not a setter
        If eventArgs.Method.Name.StartsWith("set_") Then
            notifier.OnPropertyChanged(eventArgs.Method.Name.Substring(4))
        End If
    End Sub
 
End Class

Note that when you apply PostSharp attribute to a property, you are actually applying the attribute to the two methods that are generated for that property. For example, if you have a property called MyProperty then the compiler will actually generate two methods: get_MyProperty and set_MyProperty. Since OnExit() will actually get called for both of these methods when we apply the attribute to a property, the code has to check whether the getter or the setter was called. Using the attribute is very simple:

<Notify()> _
Public Property Text() As String
    Get
        Return _text
    End Get
    Set(ByVal value As String)
        _text = value
    End Set
End Property

The result is that the PropertyChanged event will automatically be raised after the setter finishes executing and there is no need to hard code any strings! Now you are free to change the name of your property and it won’t break any code.

WPF rendering thread synchronization

Download the sample project here: WpfRenderingThreadSynchronization.zip

In most applications it is necessary to offload long running processes to an alternate thread so that the rest of the program does not lock up during that time. However, it’s not so simple when the long running process is the actual rendering. Separate windows can have their own UI threads (as explained here) but to my knowledge there is no way to use multiple rendering threads on a single window.

The second problem is that rendering is done in big chunks. For example, if you have an ItemsControl that is bound to an ObservableCollection and a loop that adds 1000 items to that collection, you will notice that the elements are not drawn one at a time. Instead the UI will stall for a moment and then every element will suddenly appear on screen. During the time that it is loading, the entire window will be completely unusable. Basically, what happens is that UI changes (like adding an element to an ItemsControl’s ObservableCollection) all get put into a queue and then the rendering thread deals with a whole bunch of them all at once.

There are two problems with this behaviour:

  • The rest of the UI is unusable while this loading takes place
  • It’s not obvious what is happening during the loading period. Since absolutely nothing is happening on screen, the user might think the app is broken.

It turns out that in cases like this where we have many small rendering operations that add up to a large amount of time, we can force the rendering thread to flush out the Windows message queue after each element is added to the collection. This will not only allow the user to see progress (ie: items appearing in the ItemsControl one at a time) but between each item being added other UI updates can take place giving the illusion that there are separate UI threads.

The included sample draws 1000 TextBoxes inside an ItemsControl, but after each element is added the Windows message queue is flushed out using the FlushWindowsMessageQueue function. All the functions does is tell the dispatcher to invoke a delegate that does nothing. The result is that the code blocks at that line until the specified delegate has been run. But since it is at the end of the queue, everything else has to be dealt with first. The function looks like this:

Private Sub FlushWindowsMessageQueue()
    Application.Current.Dispatcher.Invoke( _
        New Action(AddressOf DummySub), _
        DispatcherPriority.Background, _
        New Object() {})
End Sub
 
Private Sub DummySub()
End Sub

When the sample is run with the FlushWindowsMessageQueue() line commented out the whole UI will lock up for a couple of seconds after you click “Refresh data”. However, when the message queue is emptied after each element is added the UI never locks up, even when it is still drawing TextBoxes.

Unfortunately, there are some drawbacks to this method. The most obvious is that it makes the entire rendering operation actually take longer. The trade off is that the first items appear much earlier, but the last items appear later. The technique also cannot be used when the rendering cannot easily be split into many small chunks.

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.