Moving House …

January 20, 2009

This blog has been moved to its new and more permanent home:

http://www.scottlogic.co.uk/blog/wpf/

Please update your RSS reader and links.

Regards, Colin E.


LayoutTransform vs. RenderTransform – What’s the Difference?

December 19, 2008
This blog post has moved to its new location:

http://www.scottlogic.co.uk/blog/wpf/2008/12/layouttransform-vs-rendertransform-whats-the-difference/

Please update your bookmarks and post any comments to the article at its new location. Thanks.

I have answered a few forum posts about the WPF transforms recently, mostly regarding confusion between RenderTransform and LayoutTransform. This brief blog post illustrates the difference between the two. The WPF layout system comprises, of two steps, followed by the rendering of the user interface (UI):

  • Measure
  • Arrange
  • Render

In the Measure step, the DesiredSize of each element is computed; in the Arrange step the position of child elements within their parents is determined; finally, in the Render step, the result user interface is rendered to the screen. Layout transforms and Render transforms are computed at different stages of the layout/render process:

  • LayoutTransform
  • Measure
  • Arrange
  • RenderTransform
  • Render

As a result, any transformations associated with an elements LayoutTransform property will have an impact on the subsequent Measure and Arrange steps. Whereas a RenderTransform will not have any impact on the layout process and will only effect rendering. The difference is probably best illustrated by an example:

transforms

In the above examples, it can be seen that when a LayoutTransform is applied, neighbouring elements are re-positioned to accommodate the transformed elements, whereas with the RenderTransform they are not. One common use of WPF transforms is to rotate ListView column headings. With the above examples it should be obvious that a LayoutTransform is required to achieve this effect.

You can download the demo project, wpfrenderandlayouttransforms, changing the file extension from .doc to .zip.

Regards, Colin E.


Awards and other news

December 4, 2008

A couple of days ago I was happy to hear that I am a prizewinner in the Community Credit awards for November 2008. Community Credit encourages developers to contribute to the global developer community by writing articles, giving talks, participating on forums etc… Top contributors are rewarded with ’stupid prizes’,  I will shortly be receiving my certificate and some Wasabi flavoured gumballs:

wasabi

I have also, just yesterday, been accepted into the WPF Disciples Group. A small group of WPF enthusiasts who ‘move the world forward’ – a grand and noble tagline!

Regards, Colin E.


WPF DataGrid – detecting the column, cell and row that has been clicked

December 2, 2008
This blog post has moved to its new location:

http://www.scottlogic.co.uk/blog/wpf/2008/12/wpf-datagrid-detecting-clicked-cell-and-row/

Please update your bookmarks and post any comments to the article at its new location. Thanks.

The WPF DataGrid is a very flexible tool, however in its current state certain simple tasks can prove to be rather tricky. A fairly common task when working with DataGrid is detecting which row, or cell a user has clicked on, or whether they clicked a column header. You might expect this information to be readily available in the form of events, after all, the Windows Forms DataGridView has CellClicked and ColumnHeaderMouseClick events (among many others). However, sadly this is not the case. In order to implement this behaviour you have to understand the visual tree of the DataGrid and how it can be navigated.

Let’s say for example you wanted to find the DataGrid item (cell, row, header) that was clicked when the right mouse button is released. Firstly, we add an event handler for the mouse click in our code-behind:

XAML:

<dg:DataGrid Name="DataGrid"
             MouseRightButtonUp="DataGrid_MouseRightButtonUp"/>

C#:

private void DataGrid_MouseRightButtonUp(object sender,
                                        MouseButtonEventArgs e)
{
}

The above event is a ‘bubbling’ event, which means that it it started on the element that was originally clicked (for example a TextBlock which renders the cell’s value within a DataGridCell), then bubbled up the logical tree until it reaches our event handler in the Window. The e.OriginalSource property gives us access to the element that initiated this event.

The problem is that while we have access to the lement which was clicked on, this element is part of the control or data template of the element that we are really interested, the cell or header. The WPF rich-content model means that our cells could contain all sorts of visual element, therefore we have no way of guessing exactly what e.OriginalSource will be. However, the one thing of which we can be certain is that this element is a child of the element which we are interested in.

If you place a bearkpoint within yoru event handler, you can then use the excellent Mole debug visualiser to locate the clicked element within the visual tree as illustrated below:

dgvisualtree

As you can see, the visual tree is a complex beast! I have highlighted the items of interest:

  1. The TextBlock, which is the element I clicked on, which is e.OriginalSource parameter.
  2. The DataGridCell, the cell which was clicked on.
  3. The DataGridRow which the cell belongs to.
  4. And finally, the DataGrid.

Therefore, in order to locate the cell and row that was clicked on we must navigate up the Visual Tree, searching by type:

private void DataGrid_MouseRightButtonUp(object sender,
                                                  MouseButtonEventArgs e)
{
    DependencyObject dep = (DependencyObject)e.OriginalSource;

    // iteratively traverse the visual tree
    while ((dep != null) &&
            !(dep is DataGridCell) &&
            !(dep is DataGridColumnHeader))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    if (dep == null)
        return;

    if (dep is DataGridColumnHeader)
    {
        DataGridColumnHeader columnHeader = dep as DataGridColumnHeader;
        // do something
    }

    if (dep is DataGridCell)
    {
        DataGridCell cell = dep as DataGridCell;
        // do something
    }
}

Fantastic, we have now have our header and cell. All that’s left to do is extract the cell’s row and column indices, and cell value. Wait a minute … where are the cell.RowIndex and cell.ColumnIndex properties? It looks like there’s more work to be done.

Once we have navigated up the tree to the DataGridCell, we can continue our journey upwards to obtain the DataGridRow:

if (dep is DataGridCell)
{
    DataGridCell cell = dep as DataGridCell;

    // navigate further up the tree
    while ((dep != null) && !(dep is DataGridRow))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    DataGridRow row = dep as DataGridRow;
}

Does the DataGridRow have a RowIndex property? I think you can guess the answer to that question.

The DataGrid is an ItemsControl – WPF users are probably most familiar with the ListView which is also an ItemsControl whcih has a number of similarities with the DataGrid. In the ItemsControl terminology, the DataGridRow is an ItemContainer and the DataGrid has an ItemContainerGenerator associated with it for generating the rows. I don’t want to go into the details of how ItemContainers work, Dr. WPF has a good series on the ItemsControl for those who are interested. The following code can be used to determine the index of a row:

private int FindRowIndex(DataGridRow row)
{
    DataGrid dataGrid =
        ItemsControl.ItemsControlFromItemContainer(row)
        as DataGrid;

    int index = dataGrid.ItemContainerGenerator.
        IndexFromContainer(row);

    return index;
}

Now that we have the row index, the column index is thankfully a little easier to locate, cell.Column.DisplayIndex does the trick. The final piece of information which we might like is the cell value. Is there a cell.Value properly? don’t make me laugh!

The following method determines the property binding for the cells column, then extracts the value from the data items associated with the row:

private object ExtractBoundValue(DataGridRow row,
                                 DataGridCell cell)
{
    // find the column that this cell belongs to
    DataGridBoundColumn col =
       cell.Column as DataGridBoundColumn;

    // find the property that this column is bound to
    Binding binding = col.Binding as Binding;
    string boundPropertyName = binding.Path.Path;

    // find the object that is related to this row
    object data = row.Item;

    // extract the property value
    PropertyDescriptorCollection properties =
        TypeDescriptor.GetProperties(data);

    PropertyDescriptor property = properties[boundPropertyName];
    object value = property.GetValue(data);

    return value;
}

Putting it all together, this blog post has a small sample application which displays the header index and value, or cell’s row/column indices and value in response to a right mouse click:

clickedvalue

The sample project can be download, wpfdatagridmouseclicks, changing the file extension from .doc to .zip.

Regards, Colin E.


Using BindingGroups for greater control over input validation

November 28, 2008
This blog post has moved to its new location:

http://www.scottlogic.co.uk/blog/wpf/2008/11/using-bindinggroups-for-greater-control-over-input-validation/

Please update your bookmarks and post any comments to the article at its new location. Thanks.

In a recent post on his blog Josh Smith described a technique for providing more meaningful error messages when the type conversion process fails within the binding framework. Consider the following problem; you bind an integer property of your object (Age for example) to a TextBox within your user interface. If the user enters a non-numeric value into the TextBox an exception is thrown within the binding framework when it attempts to parse this value. The framework provide s a way of catching validation exceptions, by setting ValidatesOnExceptions to true within a binding, however the error message provided is “Input string was not in a correct format.” – this is the sort of error message that a software engineer would understand, but not the majority of the population!

standardvalidation

Josh details a technique that can be used to provide more meaningful error messages. His technique uses a View-Model (the classes which massage your data into a form which is more amenable to your presentation technology), which binds a text ‘Age’ property to ensure that there are no type conversions issues in the binding, allowing the issue of parsing errors to be managed directly. This blog post illustrates an alternative technique to his approach, using the recently introduced feature of BindingGroups.

Take for example a very simple example, a Person class which has properties of Name and Age. This class implements IDataErrorInfo, allowing us to manage validation logic within the business objects themselves. This class has a pair of simple rules which are applied to the Age property.

public class Person : IDataErrorInfo, INotifyPropertyChanged
{
    private int age;
    public int Age
    {
        get { return age; }
        set {
            age = value;
            RaisePropertyChanged("Age");
        }
    }

    private string name;
    public string Name
    {
        get { return name; }
        set {
            name = value;
            RaisePropertyChanged("Name");
        }
    }

    #region IDataErrorInfo Members
    public string Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get {
            if (columnName == "Age")
            {
                if (Age < 0)
                    return "Age cannot be less than 0.";
                if (Age > 120)
                    return "Age cannot be greater than 120.";
            }
            return null;
        }
    }
    #endregion

    #region INotifyPropertyChanged Members
    ...
    #endregion
}

An instance of the above class is displayed in a simple form using the following XAML:

<Grid x:Name="RootElement">
  <Grid.BindingGroup>
    <BindingGroup>
      <BindingGroup.ValidationRules>
        <local:PersonValidationRule
          ValidationStep="ConvertedProposedValue"/>
      </BindingGroup.ValidationRules>
    </BindingGroup>
  </Grid.BindingGroup>

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="1.8*"/>
  </Grid.ColumnDefinitions>

  <Grid.RowDefinitions>
    <RowDefinition/>
    <RowDefinition/>
    <RowDefinition/>
  </Grid.RowDefinitions>

  <Label Content="Name:"/>
  <TextBox Grid.Column="1" LostFocus="TextBox_LostFocus"
       Text="{Binding Name, ValidatesOnDataErrors=true}"/>

  <Label Grid.Row="1" Content="Age:"/>
  <TextBox Grid.Row="1" Grid.Column="1" LostFocus="TextBox_LostFocus"
       Text="{Binding Age, ValidatesOnDataErrors=true}"/>   

  <Label Grid.Row="2" Grid.ColumnSpan="2" Foreground="Red"
       Content="{Binding Path=(Validation.Errors)[0].ErrorContent,
               ElementName=RootElement}"/>

</Grid>

The TextBox bindings use ValidatesOnDataErrors, this ensures that the IDataErrorInfo interface methods on the Person class will be invoked, enforcing our Age rules. However, they do not handle exceptions thrown in the binding process, i.e. ValidatesOnExceptions is absent.

The interesting part of the above code is the BindingGroup which is present in the Grid element, i.e. at the ‘Form’ level. When you define a BindingGroup it is related to the DataContext of the element that it is defined against. The BindingGroup will then have access to all the other Bindings which relate to this DataContext. In the above example, the bindings inherit the Grid’s DataContext and are members of the same BindingGroup.

BindingGroups allow group level validation, this is useful for example if you have validation rules which relate to more than one property, for example “StartDate < EndDate”. You can read all about BindingGroups on Vincent Sibal’s Blog.

In the above example, we do not have complex validation logic, so why use a BindingGroup?

When a ValidationRule is associated with a BindingGroup it has access to both the BindingExpressions, i.e. the “Name” and “Age” bindings in our example, and the BindingGroup instance itself. This class has some very useful methods like TryGetValue, which will attempt to get the bound value from the TextBox (or other bound UI control). However, the interesting part is that you can determine at what point in the binding pipeline your validation rule is applied, which will in turn determine whether you get back the raw value from the control, for example the string “34″, or the value after it has been parsed, i.e., an integer ‘34′.

When BindingGroup was added to the API in .NET 3.5 SP1, the ValidationRule class was extended to add a ValidationStep property. This enumeration indicates at what stage within the binding pipeline a particular rule is invoked. The four possible enumeration values are detailed on MSDN. The one which we are interested in here is ConvertedProposedValue, which will mean that our rule is invoked after the binding framework has parsed the input string to an integer.

Here is our validation rule:

public class PersonValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value,
                                             CultureInfo cultureInfo)
    {
        BindingGroup bindingGroup = (BindingGroup)value;
        Person person = (Person)bindingGroup.Items[0];

        // validate the age
        object objValue = null;
        if (!bindingGroup.TryGetValue(person, "Age", out objValue))
        {
            return new ValidationResult(false, "Age is not a whole number");
        }

        // if we can retrieve the value - can we parse it to an int?
        int parseResult;
        if (!Int32.TryParse(objValue as string, out parseResult))
        {
            return new ValidationResult(false,
                            string.Format("Age is not a whole number"));
        }

        return ValidationResult.ValidResult;
    }
}

In the above code we ask the BindingGroup to provide its proposed value for the Age property. If the user has input a non-numeric value, TryParse will fail. We can then catch this failure and provide a suitable error message.

The final piece of the puzzle is dictating when this BindingGroup runs its associated rules. One of the primary purposes of the bindingGroup is to allow transactional editing of objects, for example within the WPF DataGrid it is used to commit a Row as a ‘atom’. We must manually commit this BindingGroup in order to run our rule, a ‘Submit’ button could be added to our form, but for simplicity in this example I simply commit as each TextBox loses focus:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    RootElement.BindingGroup.CommitEdit();
}

When using BindingGroups we can still of course validate each Binding independently, our ValidatesOnDataErrors still works.

The finished result is shown below, the screenshot on the right shows how our rule within the BindingGroup catches the case where the string cannot be parsed, and on the left where our Age rule enforced via IDataErrorInfo is violated.

bindinggroupvalidation

You can download a demo project with all of this code – bindinggroupvalidation, simple change the file extension from .doc to .zip.

*phew* – I thought I started writing a blog so that I could avoid writing lengthy articles!

Regards, Colin E.


Design time drag-and-drop binding is on its way

November 27, 2008

In my opinion the lack of decent design-time tool support is currently hampering the adoption of WPF, that and the relatively small number of controls available to the developer out-of-the-box. The later is being addressed to a certain extent by the developer community, notably by Marlon Grech’s Avalon Controls Library and the WPF Toolkit. The former, design-time support, is something that is harder for the developer community to address, however Karl Shifflet’s XAML Power Toys, which add drag and drop form generation make a pretty good stab at it.

Despite this, people are adopting WPF even though it is not RAD yet. Paul Stovell provides a great demonstration of how productive WPF really is.

However; there are interesting developments at Microsoft, a video on Channel 9 reveals that Drag-Drop Data Binding will com to WPF in Visual Studio 2010. Exciting news indeed!

The screenshot below shows a Window which contains two ListViews in a master-detail configuration, which was entirely developed by drag and drop (minus a few code tweaks due to minor bugs in the VS 2010 CTP):

dragdropbinding

The demonstration details how DataSets, ADO.NET Entities, or Objects can be bound – with master-detail view achieved by ‘chaining’ CollectionViewSources, in the same way that you would a Windows Forms BindingSource. All this will sound familiar (and cosy) to a Windows Forms developer.

I am guessing that VS2010 will also provide the same drag and drop support for the WPF DataGrid.

While this looks like excellent news, drag and drop is not the be-all and end-all of RAD application development. Once you have dragged your UI elements onto the Window you would also want to be able to re-configure the source of the bindings, or the bound properties without having to touch the XAML. I do hope that VS 2010 brings this functionality also.

Either way, VS 2010 should open up WPF to a whole new audience.

Regards, Colin E.


Multiselect DataGrid with CheckBoxes

November 26, 2008
This blog post has moved to its new location:

http://www.scottlogic.co.uk/blog/wpf/2008/11/multiselect-datagrid-with-checkboxes/

Please update your bookmarks and post any comments to the article at its new location. Thanks.

I am currently very interested in the new WPF DataGrid which was released on codeplex recently. Someone posted an interesting question in the codeplex forums asking about whether it would be possible to configure the DataGrid so that a user can make multiple row selections via checkboxes which are associated with each row. I thought that this sounded like an excellent idea – afterall, the standard behaviour of ctrl-leftclick might be intuitive to the computer savvy, however you can bet the average user (which is certainly the majority) does not know this.

Fortunately the solution is quite simple to implement in WPF:

<dg:DataGrid ItemsSource="{Binding}">
  <dg:DataGrid.RowHeaderTemplate>
    <DataTemplate>
      <Grid>
        <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                  RelativeSource={RelativeSource FindAncestor,
                  AncestorType={x:Type dg:DataGridRow}}}"/>
      </Grid>
    </DataTemplate>
  </dg:DataGrid.RowHeaderTemplate>
</dg:DataGrid>

The above code provides a DataTemplate for the RowHeader allowing us to render a CheckBox for each row. The IsChecked property uses a RelativeSource binding which navigates the Visual Tree to locate the first ancestor of type DataGridRow. From here the IsSelected property which dictates that the selected state of the row is available. The binding is TwoWay so that ctrl-leftclick behaviour is still visible.

The result is illustrated below:

multiselect

The above example is a concise illustration of the beauty of WPF. Performing the above customisation of the DataGridView in Windows Forms would be at least an afternoons work. However the solution is not without its problems, if you try the above you will find that the checkboxes are rather difficult to click on because the mouse cursor will be displaying the up-down arrow that indicates that it is currently over the gripper that allows you to specify the row height.

Finding the cause of this means delving deep into the DataGrid control templates …

The template for the DataGridRowHeader is given below (in edited form):

<Style x:Key="{x:Type dgp:DataGridRowHeader}"
       TargetType="{x:Type dgp:DataGridRowHeader}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type dgp:DataGridRowHeader}">
        <Grid>
          ... snipped header content + validation error indicator ...
          <Thumb x:Name="PART_TopHeaderGripper"
                 VerticalAlignment="Top"
                 Style="{StaticResource RowHeaderGripperStyle}"/>
          <Thumb x:Name="PART_BottomHeaderGripper"
                 VerticalAlignment="Bottom"
                 Style="{StaticResource RowHeaderGripperStyle}"/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

The header template includes a pair of grippers. The visible state of these is toggled depending on the row’s location (i.e. there is no top gripper on the first row), and whether the DataGrid CanResizeRows is true.

The RowHeaderGripperStyle specifies a Transparent background for the grippers which renders them invisible. If we change this to Green we can see the culprits:

datagridselectproblem

In order to allow our Checkboxes to be clickable, we simply reduce the height of the grippers as follows:

<Style x:Key="RowHeaderGripperStyle" TargetType="{x:Type Thumb}">
  <Setter Property="Height" Value="2"/>
  <Setter Property="Background" Value="Green"/>
  <Setter Property="Cursor" Value="SizeNS"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Thumb}">
        <Border Padding="{TemplateBinding Padding}"
                Background="{TemplateBinding Background}"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Unfortunately this means that we have to duplicate the DataGrid parts; the DataGridRowHeader template and the above style, in order to perform this customisation. The Beauty of XAML and a Beast of a control template!

You can download the demo project, wpfdatagridmultiselect, changing the file extension from .doc to .zip.

Regards, Colin E.

P.S. You can achieve the same effect with a ListView as detailed in this blog post.


Hello World

November 26, 2008

Welcome to the birth of my blog, “Adventures in WPF”. This is the first blog I have started for the very good reason that up until now i have not found anything that I really feel like blogging about!

However, this all changed when I started to learn Windows Presentation Foundation (WPF), the new presentation framework from Microsoft. In my opinion this framework has greater depth and beauty than any other User interface (UI) framework I have worked with before.

I have already authored a number of well received WPF articles which you can find on codeproject. However, writing a full-blown article takes a lot of effort. I intend to use this blog for sharing thoughts, ideas, tips and tricks that are either to small for crafting into an article, or if I simply do not have the time. Now all I have to do is learn the difference between trackbacks and pingbacks and I can get started …

I am always happy to receive feedback – so please leave a comment or send me a mail.

Regards, Colin E.