WPF Sample Series – ListBox Grouping, Sorting, Subtotals and Collapsible Regions

June 10, 2009

This is the next sample in the WPF Sample Applications Series. The purpose of the Sample Series is to provide concise code solutions for specific programming tasks. This sample provides a brief description of the problem, the solution and full source code.


These past few months I’ve been privileged to be a part of the WPF for Line of Business Training Tour.  What I really love is to be around developers excited about the WPF platform.  At each city I got requests from attendees to show them how to accomplish a task in WPF.  During a break I would sit down and write the code and usually I add the code to the session downloads.

This sample is the result of the question, “how can I do multi-level grouping?”


All regions have been collapsed.  Count of Account Mangers is displayed along with the sales in dollars.


The West region has been expanded along with the child states.  Notice the state grouping level has totals for its state.  Account Manages have their name and sales figure displayed.


Application Requirements

  • Grouping levels must be collapsible
  • Display total sales for Account Managers in the level
  • Display count of Account Managers in the level
  • Display the familiar “+” and “-” icon for expanding and collapsing levels
  • Sort data by region, state and sales descending

Grouping and Sorting

<CollectionViewSource Source="{x:Static local:Data.AccountManagers}" x:Key="cvs">
        <scm:SortDescription PropertyName="Region" />
        <scm:SortDescription PropertyName="State" />
        <scm:SortDescription PropertyName="Sales" Direction="Descending" />
        <PropertyGroupDescription PropertyName="Region" />
        <PropertyGroupDescription PropertyName="State" />

WPF provides the CollectionViewSource for codeless sorting and grouping of data.  The SortDescriptions and GroupDescriptions collections can be modified at runtime if desired.  The SortDescription provides the ability to set the sort direction as I’ve done for the Sales.

The ListBox consumes the CollectionViewSource data by assigning the ListBox.ItemsSource property to the CollectionViewSource resource.

Note:  I’ve assigned the Source to a static property so that I can have design time data and rending of the ListBox during development.


The ListBox.GroupStyle does all the heaving lifting for rendering the group level headers.  You have several options when working with GroupStyles. 

  • Define a GroupStyle.HeaderTemplate
  • Define a GroupStyle.ContainerStyle
  • Use a HeaderTemplateSelector to select the HeaderTemplate at runtime
  • Use a ContainerStyleSelector to select the ContainerStyle at runtime

For this application, I’ve chosen to define a ContainerStyle in XAML.

When defining a ContainerStyle, we will re-template the GroupItem that gets created for each level of grouping.

The purpose of re-templating the GroupItem is so that we have full control over how level is rendered.

      <Style TargetType="{x:Type GroupItem}">
        <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type GroupItem}">
                <DataTrigger Binding="{Binding Path=IsBottomLevel}" Value="True">
                  <Setter TargetName="gridTemplate" Property="Grid.Background"
                          Value="#FF965F00" />
                  <RowDefinition />
                  <RowDefinition />
                <Grid Background="Black" x:Name="gridTemplate" Height="26"
                    <Style TargetType="{x:Type TextBlock}">
                      <Setter Property="FontSize" Value="14" />
                      <Setter Property="Foreground" Value="White" />
                      <Setter Property="VerticalAlignment" Value="Center" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="45" />
                    <ColumnDefinition Width="30" />
                    <ColumnDefinition Width="110" />

                  <ToggleButton x:Name="btnShowHide" IsChecked="True" Margin="3.5" />

                  <TextBlock Grid.Column="1" Text="{Binding Path=Name}" Margin="3.5,0" />
                  <TextBlock Grid.Column="2" Text="Count:" />
                  <TextBlock Grid.Column="3" Text="{Binding Path=ItemCount}"
                             TextAlignment="Right" Margin="0,0,11,0" />
                  <TextBlock Grid.Column="4"
                             Text="{Binding StringFormat=\{0:C\},
                            Converter={StaticResource groupItemSalesSubtotalConverter}}"
                             TextAlignment="Right" />

                  Visibility="{Binding ElementName=btnShowHide,
                                Converter={StaticResource booleanToVisibilityConverter}}"
                  Grid.Row="1" Margin="11,0,0,3.5" />


The DataContext for a GroupItem is a CollectionViewGroup.

In this ControlTemplate we will bind to the following properties of the CollectionViewGroup:

  • IsBottom – used by DataTrigger to set level heading Background
  • Name – used to display the level’s heading text
  • ItemCount – used to display the number of members in this level
Collapsible Group Levels

The ToggleButton has been re-templated to display an image that indicates the state of the Button.  (see download for template)

The ItemsPresenter at the bottom of the template is where the data items will be rendered. 

Using the built-in BooleanToVisibilityConvert and binding the ItemsPresenter.Visibility property to the ToggleButton.IsChecked property, we get simple, codeless collapse and expand behavior of the data members.

You really have to admire the sheer power of WPF here.


The last TextBlock Text property has a strange Binding.  There is no path.  When the converter is called, the DataContext will be passed as the value to the converter.  In this code the CollectionViewGroup will be passed to the converter.

Imports System.Windows.Data

<ValueConversion(GetType(CollectionViewGroup), GetType(Double))> _
Public Class GroupItemSalesSubtotalConverter
  Implements IValueConverter

  Public Function Convert( _
    ByVal value As Object, ByVal targetType As System.Type, _
    ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
      As Object Implements System.Windows.Data.IValueConverter.Convert

    If value IsNot Nothing AndAlso TypeOf value Is CollectionViewGroup Then
      Return GetSubTotal(DirectCast(value, CollectionViewGroup))
      Return Nothing
    End If

  End Function

  Private Function GetSubTotal(ByVal obj As CollectionViewGroup) As Double

    Dim dbl As Double
    For Each objItem As Object In obj.Items
      If TypeOf objItem Is AccountManager Then
        dbl += DirectCast(objItem, AccountManager).Sales
        dbl += GetSubTotal(objItem)
      End If
    Return dbl
  End Function

  Public Function ConvertBack( _
    ByVal value As Object, ByVal targetType As System.Type, _
    ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
      As Object Implements System.Windows.Data.IValueConverter.ConvertBack

    Throw New NotImplementedException

  End Function

End Class

This converter uses recursion to drill down to each member of the level and calculate a sales subtotal.


      <TextBlock DockPanel.Dock="Right" HorizontalAlignment="Right"
                 Text="{Binding Path=Sales, StringFormat=C}" />

      <TextBlock Text="{Binding Path=FullName}" />


The ListBox.ItemTemplate is used when rendering the AccountManager data items.  A DockPanel provides the required layout.  The TextBlocks are data bound to properties on the AccountManager class.


After downloading you must change the file extension from .doc to .zip.  This is a requirement of WordPress.com

Source Code (32KB)

Hope you can learn a little more about WPF from this article and the Sample Series.

Have a great day,

Just a grain of sand on the worlds beaches.

Los Angeles WPF LOB Tour Downloads

April 29, 2009

We have posted the slide decks, lab walk through, sample MVVM applications and class code at the following two links.

 Slide Decks

Code and Demos

Jaime also did a nice blog post here, thanking all attendees!

Have a great day,

Just a grain of sand on the worlds beaches.

Ocean Framework Released – MVVM for WPF Line of Business Update

January 26, 2009



As part of my new MVVM articles, I’m posting the Ocean Framework source code.  The Ocean Code Generation pieces will follow in February.

The M-V-VM Home Page has been updated.

The WPF Line of Business – Demo Application Source has been posted.  (Ocean Framework source is part of this.)

The WPF Line of Business – Introduction as been posted.

This series of MVVM articles targets those unfamiliar with MVVM or who are learning this wonderful WPF UI Design Pattern.


I hope you find this material useful and can learn more about MVVM and WPF from it.

Have a great day!

Just a grain of sand on the worlds beaches.

WPF Sample Series – Using WPF Binding StringFormat Property with Nullable Types

December 16, 2008

One of the great features introduced in .NET 3.5 Framework Service Pack 1 is the BindingBase StringFormat property.  When used in a data binding expression the StringFormat property replaces most IValuteConverters that were used for formatting of values in  WPF 3.0 & WPF 3.5 applications.

Here are two examples of the StringFormat property in action formatting a currency field:

<TextBox Text="{Binding Path=Salary, StringFormat=c}" />

<TextBox Text="{Binding Path=Salary, StringFormat=\{0:c\}}" />

Nullable Type in the Mix

If you are binding to a non-Nullable data type the above will work just fine.

However, if you are binding to a Nullable data type the above will not work.

This breaks down when a UI Control like a TextBox as a value and the user clears the TextBox and press TAB.  The default implementation of StringFormat will attempt to set the Target Property to an empty string which in the the case of a Nullable Decimal property will cause the following or similar data binding exception.  The below data binding exception can be viewed in the Visual Studio Output window.


System.Windows.Data Error: 7 : ConvertBack cannot convert value ” (type ‘String’). BindingExpression:Path=Age; DataItem=’Customer’ (HashCode=31884011); target element is ‘TextBox’ (Name=”); target property is ‘Text’ (type ‘String’) FormatException:’System.FormatException: Input string was not in a correct format.

at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)

at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)

at System.String.System.IConvertible.ToInt32(IFormatProvider provider)

at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)

at MS.Internal.Data.SystemConvertConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)

at System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)’

TargetNullVaue to the Rescue

In the above example, the exception is thrown because of a type mismatch.  In WPF 3.0 and 3.5 I had a set of Nullable ValueConverters for my applications to handle this problem.

Another great feature introduced in .NET 3.5 Framework Service Pack 1 is the BindingBase TargetNullValue property.  This property can be used to handled the type mismatch problem when converting an empty string from a TextBox to Nothing (null) when the binding pipeline sets the target Nullable property.

Let’s have a look at the two below TextBoxes.

    Text="{Binding Path=NumberOfComputers,
            TargetNullValue={x:Static sys:String.Empty},
            StringFormat=\{0:D\}}" />

    Text="{Binding Path=Age, StringFormat=\{0:D\}}" />

These TextBoxes are both bound to Nullable properties.  The first TextBox takes advantage of the TargetNullValue property and works as expected.  The second does not.   The data binding pipeline will throw an exception when the second TextBox is changed to an empty string and it attempts to assign the value of String.Empty to the Target property.

Here is a potential problem.  If the exception gets thrown and swallowed because the code didn’t check for this, the user thinks they cleared a value but the property the TextBox is bound to never gets changed due to the exception being thrown.


I’ve included a very simple project that you can download a play with.

After downloading the project, please change the extension from .doc to .zip.  This is a requirement of WordPress.com.

Download Sample Project (76KB)

Steps To Reproduce Issue

Launch included program using debug mode.

Ensure Visual Studio Output window is visible.

Set each TextBox to 7.

Go to first TextBox.  Clear field and press TAB.  Notice nothing is added to the Output window.

Go to second TextBox.  Clear field and press TAB.  Notice nothing an exception is added to the Output window.


When binding to Nullable types, use the TargetNullValue property along with the StringFormat property to avoid type mismatch exceptions.

Hope this tip has helped you learn more about WPF!

Have a great day!

Just a grain of sand on the worlds beaches.

WPF Sample Series – Solution for the Obsolete BitmapEffect Property and Rendering an OuterGlowBitmapEffect

November 4, 2008

Since the release of .NET 3.5 SP1, I have been getting a new Visual Studio warning in my code where I have assigned a BitmapEffect to a UIElement.  Specifically I was using the OuterGlowBitmapEffect.

Warning 1 ‘Public Property BitmapEffect() As System.Windows.Media.Effects.BitmapEffect’ is obsolete: ‘Avoid using BitmapEffects as they have very poor performance characteristics.  They will be deprecated in a future version.  Consider using the UIElement.Effect property and ShaderEffects where appropriate instead.’


I needed an outer glow effect in my application so I read up on the new Effects property and the new Effect and ShaderEffects classes.  However, I could not find a replacement for the OuterGlowBitmapEffect that would work with the new UIElement.Effects property.

UIElement.BitmapEffect property is obsolete, making those bitmap effects we have been using obsolete also.

On the surface it seems the new UIElement.Effect property does not have an OuterGlowEffect class we can use to replace the OuterGlowBitmapEffect we have been using.


Today I was reading a WPF thread and found the solution that I want to share with you.


The simple example has four buttons, two with effects declared in  XAML the other two effects assigned in code.  When using the obsolete BitmapEffect property in XAML, no warnings are given by Visual Studio.  The warnings are only provided when you assign the BitmapEffect property a value in code.

Most of you are familar with the OutGlowBitmapEffect.  There is no new class deriving from Effect or ShaderEffect that has a name with OuterGlow in it.

The solution is to use the new DropShadowEffect and set its ShadowDepth to zero.  Presto, we not have an outer glow effect we need.  You can also play around with the BlurRadius property to get the glow size you want.

Here is the best part of all, your outer glow will now be hardware rendered and not software rendered, giving you a nice performance boost. 

You can read about the hardware performance boost in this post GPU-Accelerated Custom Effects for WPF.

<Window x:Class="Window1" 
    Title="Window1" Height="300" Width="300">
    <Button Margin="11" Content="OuterGlowBitmpEffect - XAML">
        <OuterGlowBitmapEffect GlowColor="Blue" GlowSize="5" />

    <Button Margin="11" Content="DropShadowEffect - XAML">
        <DropShadowEffect ShadowDepth="0" Color="Blue" BlurRadius="10" />

    <Button Margin="11" Content="OuterGlowBitmpEffect - Code" x:Name="btnOuterGlow" />

    <Button Margin="11" Content="DropShadowEffect - Code" x:Name="btnDropShadow" />


The below line of code, Me.btnOuterGlow.BitmapEffect = objOutGlow gets flagged by Visual Studio with the warning message in the below comment.

Below the comment is the code for assigning the new DropShadowEffect to the button in code.  By setting the ShadowDepth to zero and increasing the BlurRadius to ten, you get the same outer glow effect you had with the now obsolete OuterGlowBitmapEffect .

Imports System.Windows.Media.Effects

Class Window1

    Private Sub Window1_Loaded(ByVal sender As Object, _
            ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim objOuterGlow As New OuterGlowBitmapEffect
        objOuterGlow.GlowSize = 5
        objOuterGlow.GlowColor = Colors.Red
        Me.btnOuterGlow.BitmapEffect = objOuterGlow

        'Public Property BitmapEffect() As System.Windows.Media.Effects.BitmapEffect
        ' is obsolete.  Avoid using BitmapEffects as they have very poor performance 
        'characteristics.  They will be deprecated in a future version.  

        'Consider using the UIElement.Effect property and ShaderEffects where appropriate 

        Dim objDropShadow As New DropShadowEffect
        objDropShadow.ShadowDepth = 0
        objDropShadow.BlurRadius = 10
        objDropShadow.Color = Colors.Red
        Me.btnDropShadow.Effect = objDropShadow

    End Sub
End Class


After downloading the below package, you must rename it from .doc to .zip.  This is a requirement of WordPress.com

Download Source (17 KB)


Have a great day,

Just a grain of sand on the worlds beaches.

WPF Multi-Tier Business Application Track Code Camp Source Code

May 16, 2008

This blog post contains the source code for three of the May 17th 2008, Charlotte Code Camp sessions.  I have also included a short video below that introduces this application.

In about a week, I’ll post links to videos of all six sessions from the WPF Multi-Tier Business Application Track.  Josh Smith and I each did three sessions at in this track.


  • Visual Studio 2008
  • Infragistics xamDataGrid version 7.2. 
    • This is a free data grid for WPF that you can download Infragistics xamDataGrid here. 
    • If you have the Infragistics .NET Advantage for WPF Volume 7.2 you do not need to download the data grid.
    • Note:  you may need to reset the Infragistics references in this application if you have downloaded the free version of xamDataGrid.

The xamDataGrid is used in two of the application forms.


The included application was used instead of PowerPoint slides during the Code Camp.  It also contains a demo sales application that uses each of the features of the provided library.  The application uses many of the WPF features I’ve been blogging and writing Code Project articles on over the last few months and consolidates them into an application.

I strongly recommend that you view the above Code Camp videos when I post them.  They will help you get started and fully understand this application and all the very powerful time/code saving features.

This application is written to show WinForms developers how to accomplish familiar programming tasks in WPF.  WPF is fully ready and provides a super platform for developing line of business applications.  In case you are wondering, I keyed in the XAML by hand.  I didn’t use Expression Blend or my code generator.  I’ve been spending so much time writing code that it was nice to get back into working with XAML.

The data for this application is stored in the \bin directory of the application in the DatabaseEngineData.xml file.  If you delete the file, the database will be recreated for you when the application starts.


The above image shows the Sales Person Maintenance form using the xamDataGrid.  The data grid is fully editable and supports business object validation using the IDataErrorInfo interface.


The above image show a busy application with six open forms.  The Task Switcher allows the user to easily task switch between open forms in the application.


Silverlight Icon

The video links require Microsoft Silverlight 1.0. If you do not have it, you will be prompted to install it when you click one of the links. After the short installation is completed, close the browser window that you did the install in and re-click the video you want to watch. You can also download it here. Windows XP or Vista required.

Application Overview and Introduction


Source Code: After downloading the source code you MUST change the file extension from .zip.DOC to .zip. This is a requirement of WordPress.com.

Download Visual Studio 2008 Source 660KB

I hope that this demo application gives you a some more understanding of WPF and how WPF can be used to create line of business applications.

Have a great day!

Just a grain of sand on the worlds beaches.

Sample Series – IDataErrorInfo and the Infragistics xamDataGrid

May 15, 2008

This is the next sample in the Sample Applications Series. The purpose of the Sample Series is to provide concise code solutions for specific programming tasks. This sample provides a brief description of the problem, the solution and full source code.

I have been preparing for this weekends Code Camp in Charlotte, NC and wanted to use the Infragistics xamDataGrid in my example code.  That code will be posted here on 16 May 2008.

All of my business objects implement the System.ComponentModel.IDataErrorInfo interface.  This interface provides a simple UI agnostic method of validating business objects.

Currently the Infragistics xamDataGrid does not directly support the IDataErrorInfo interface.  (By the way, this awesome data grid is free.)

I did not want to imbed my business logic in my UI so I’ve come with a way to get the xamDataGrid to cleanly support the IDataErrorInfo interface.

If you are not familiar with the IDataErrorInfo interface, please read up on this very cool interface before proceeding.

System Requirements

You MUST have the Infragistics free xamDataGrid or .NET Advantage for WPF Volume 2 installed on your system to compile and run this application.

If you are using the free xamDataGrid you may need to change the references to the Infragistics libraries.  I’m not sure if the names match or not.

Sample Application


The above image shows a xamDataGrid with several rows.  Each row’s DataItem is an instance of the SalesPerformance class.


This simple class has two data properties ProductLineId and SalesAmount along with the IDataErrorInfo.Item and IDataErrorInfo.Error property.

The ProductLineId property is the foreign key to the ProductLine.ProductLineIdent field.  This value is used by the Product Line ComboBox to display the ProductLine.Name.

This is a very typical scenario found in business applications that uses a normalize database.

Row Editing


In the above image, the user has selected a value in the Product Line ComboBox that does not meet the validation rules for the SalePerformance.ProductLineId property.

The ComboBox now has a red border.  In addition, the user can’t edit any other row until this row is valid.

The Sales Amount field also has a validation rule that requires the value to be greater than or equal to zero.

xamDataGrid Timing Cycle

When you perform an edit on a cell the following events are raised in this order.

  • xamDataGrid:  RecordUpdating
  • xamDataGrid:  EditModeEnded

So our code must be able to manage the process using the above events in the order that the xamDataGrid raises them.  For those who are wondering, I don’t use the EditModeEnding event because the value in the bound DataItem has not yet been changed.  Since the property value is not reflected in EditModeEnding, validating the object in that event handler will do us no good.

RecordUpdating Event Handler

    Private Sub xdgSalesPerformance_RecordUpdating(ByVal sender As System.Object, _
                   ByVal e As Infragistics.Windows.DataPresenter.Events.RecordUpdatingEventArgs)

#If DEBUG Then
        Debug.WriteLine("xamDataGrid:  RecordUpdating")
#End If

        'if there are errors on the object, cancel the update.  
        'this keeps the user from editing other records until this record is corrected
        If DirectCast(DirectCast(DirectCast(e.Record,  _
            Infragistics.Windows.DataPresenter.DataRecord).DataItem, System.Object),  _
            IDataErrorInfo).Error.Length > 0 Then
            e.Action = _
        End If

    End Sub

The above event handler is very simple.  It gets a reference to the DataItem and casts it as an IDataErrorInfo.

The RecordUpdating method is the icing on the cake.  If the e.Action is canceled, the xamDataGrid will not allow the user to edit another row in the xamDataGrid until the current row is corrected.

EditModeEnded Event Handler

    Private Sub xdgSalesPerformance_EditModeEnded(ByVal sender As System.Object, _
                  ByVal e As Infragistics.Windows.DataPresenter.Events.EditModeEndedEventArgs)

#If DEBUG Then
        Debug.WriteLine("xamDataGrid:  EditModeEnded")
#End If

        'get the data object
        Dim obj As IDataErrorInfo = DirectCast(DirectCast(DirectCast( _
            DirectCast(e.Cell, Infragistics.Windows.DataPresenter.Cell).Record,  _
            Infragistics.Windows.DataPresenter.DataRecord).DataItem, System.Object),  _

        'query the objects IDataErrorInfo.Item property for any errors on this column's data
        Dim strErrorMessage As String = obj.Item(DirectCast(DirectCast( _
            e.Cell, Infragistics.Windows.DataPresenter.Cell).Field,  _

        If strErrorMessage.Length > 0 Then
            'indicate a data entry problem
            e.Editor.BorderBrush = Brushes.Red

            'save the current tooltip
            If e.Editor.ToolTip IsNot Nothing Then
                e.Editor.Tag = e.Editor.ToolTip
            End If

            e.Editor.ToolTip = strErrorMessage


            If e.Editor.Tag IsNot Nothing Then
                e.Editor.ToolTip = e.Editor.Tag
                e.Editor.Tag = Nothing

                e.Editor.ToolTip = Nothing
            End If

            'clear the data entry problem indicator
            e.Editor.BorderBrush = Nothing
        End If

    End Sub

This is another super simple event handler.

This code gets a reference to the DataItem, validates the value using the IDataErrorInfo.Item property and then sets or removes the error visual clue in the UI.


Source Code: After downloading the source code you MUST change the file extension from .zip.DOC to .zip. This is a requirement of WordPress.com.

Download Visual Studio 2008 Source 23KB

You can see how very simple it was to get the xamDataGrid to work with your business objects that support IDataErrorInfo interface.  After looking at what I’ve done, you can see that extending the xamDataGrid to encapsulate this behavior wouldn’t take but a few minutes.

Maybe in the future Infragistics can provide support for the IDataErrorInfo interface.  Possibly a property on a column that indicates that this column should be validated using IDataErrorInfo interface.  A nice ValidationErrorTemplate like the WPF controls have might also be possible instead of hard coding the border color to red.

We front line developers need to let our software tools vendors like Infragistics and Microsoft know that built in support for IDataErrorInfo is required and greatly simplifies business application development.

Hope you can learn just a little bit more about .NET from this article and the Sample Series.

Just a grain of sand on the worlds beaches.


Get every new post delivered to your Inbox.

Join 255 other followers