Archive

Archive for the ‘C#’ Category

Pluralization Services

 

Sometimes it is useful to allow a user to define their own entities or rename existing entities within an application. For example, in a contact management system, one could envisage the user wanting to tailor the software to change, say, ‘customer’ to ‘client’, or ‘lead’ to ‘prospect’, as well as defining new entities, such as contact methods, e.g. ‘network meeting’, ‘mailshot’, etc.

One issue when giving end users freedom like this is how to pluralise the words, e.g. “You have 3 new lead”. One way is to just add an ‘s’ in brackets, such as “you have 3 new lead(s)”, but this falls down with some words, such as ‘entity’, ‘person’, ‘child’, etc. where the plurals don’t follow the simple “add an ‘s'” rule.

Luckily, but for English only, .Net includes a pluralisation service which was required for the development of Entity Framework, and we can access it.

The screenshot below shows a very simple demonstration application (which can be downloaded here).

 

 

The code extract below is the key to using the service, and it is very simple.

private void buttonPluralize_Click(object sender, EventArgs e)
{
  if (!String.IsNullOrWhiteSpace(textBoxSingular.Text)) {
    textBoxPlural.Text = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en-us")).Pluralize(textBoxSingular.Text);
  } else {
    textBoxPlural.Text = String.Empty;
  }
}

 

Unfortunately, the only cultures supported at the minute are English based. If you attempt to use anything else you will be met with the lovely message “We don’t support locales other than english yet”.

To utilise the PluralizationService you need to reference the following two DLLs.

System.Data.Entity.dll
System.Data.Entity.Design.dll

On my machine, these can both be found in the following folder:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\

The second DLL, ‘System.Data.Entity.Design.dll’, is not in the .Net 4 Client framework, but rather the full framework.

You will also require the following ‘using’ statements.

using System.Data.Entity.Design.PluralizationServices;
using System.Globalization;

 

So, play around and have fun. It would be great to hear what people are doing with the service, so please let me know if you have time.

Downloads

Pluralization.zip

XamlParseException – ‘The invocation of the constructor on type…’ – A common bug

June 3, 2011 7 comments

There is an exception which many people hit when first creating dependency properties.

System.Windows.Markup.XamlParseException: The invocation of the constructor on type ‘[type name here]’ that matches the specified binding constraints threw an exception.

Don’t worry – it’s very easy to fix and also very commonly made.

You first dependency property may look something like this, especially if you use the code snippet “propdp“.

        public long MyProperty
        {
            get { return (long)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register(
                "MyProperty",
                typeof(long),
                typeof(MyClass),
                new PropertyMetadata(0));

If you created your code using the code snippet it will compile just fine and the world will be a happy place. The problem lies in the constructor of the PropertyMetadata on line 12 above where you set the default value for the property.

The definition of the constructor is:

public PropertyMetadata(object defaultValue);

The type of the parameter ‘defaultValue‘ is ‘object‘, this means that your default value will be boxed as an object type.

The error comes when the default value is needed and is unboxed. If you didn’t carefully force the type of the value going in then the most sensible type will be chosen by the compiler, which may differ from the type you specified on line 10, i.e. the underlying type you wish to use for your dependency property.

Using the above as an example, the default value is set to ‘0‘ – the compiler will interpret ‘0‘ to be an Int32 and then the constructor will store that Int32 typed value as the default value in the defaultValue object.

When you come to need the default value the code that is executed behind the scenes will attempt to turn your default value back to the type specified for your dependency property, i.e.

long value = (long)defaultValue;

Much to many people’s surprise, this is not possible and will throw the exception above. Why? Well, you need to unbox back to the underlying type before you cast it to another type.

Take the following code, which you can paste into a console project to check out:

var myInt = 0;
Console.WriteLine(myInt.GetType().Name); // produces Int32

object myObj = myInt;
Console.WriteLine(myObj.GetType().Name); // produces Int32 - the underlying type

// no problem
long myLong1 = (long)myInt;

// no problem - unboxing to int and then casting to long
long myLong2 = (long)(int)myObj;

// exception - can't unbox to a different type
long myLong3 = (long)myObj;

Note that on line 1 I declared the variable using var instead of int, however we can still see that the compiler has decided that Int32 is the best way to go with this value.

So, back to the exception, and how to correct it. Simple really, make sure that the compiler is aware of the type of value that you are passing in and make sure that it matches the type you are declaring for your dependency property.

In the example above we only need to replace line 12 with the following using an explicit cast.

                new PropertyMetadata((long)0));

Alternatively we could have used a type suffixes as a shortcut.

 new PropertyMetadata(0l));

Other type suffices are:
u – uint
l – long
ul – ulong
f – float
d – double
m – decimal

If you are interested in a more depth article on boxing and unboxing and casting in general, see Eric Lippert’s excellent blog post.

WPF, MVVM and the TreeView Control using with different HierarchicalDataTemplates and DataTemplateSelector – Reloaded

June 1, 2011 1 comment

In this previous post I outlined a way to work with the TreeView control in an MVVM fashion. In order to make any sense of this post you will need to refer to the previous one.

The code, in order to keep it simple, was quite verbose.

This post is really to outline a shorter, more generic, but more complex version of the hierarchy building code as per Listing 1 below.

public class HierarchyViewModel : ViewModelBase
{
    public CollectionView Customers { get; private set; }
    private HierarchyItemViewModel _selectedItem;

    public HierarchyViewModel(List customers, object selectedEntity)
    {
        var customerHierarchyItemsList = BuildHierarchyList<Customer>(customers, ((a, b) => a.Number == b.Number), selectedEntity,
            x => BuildHierarchyList<Order>(x.Orders, ((a, b) => a.Number == b.Number), selectedEntity,
                y => BuildHierarchyList<Product>(y.Products, ((a, b) => a.GetHashCode() == b.GetHashCode()), selectedEntity, null)
            )
        );

        this.Customers = new CollectionView(customerHierarchyItemsList);

        // select the selected item and expand it's parents
        if (_selectedItem != null)
        {
            _selectedItem.IsSelected = true;
            HierarchyItemViewModel current = _selectedItem.Parent;

            while (current != null)
            {
                current.IsExpanded = true;
                current = current.Parent;
            }
        }
    }

    private List<HierarchyItemViewModel> BuildHierarchyList<T>(List<T> sourceList, Func<T, T, bool> isSelected, object selectedEntity, Func<T, List<HierarchyItemViewModel>> getChildren)
    {
        List<HierarchyItemViewModel> result = new List<HierarchyItemViewModel>();

        foreach (T item in sourceList)
        {
            // create the hierarchy item and add to the list
            var hierarchyItem = new HierarchyItemViewModel(item);
            result.Add(hierarchyItem);

            // check if this is the selected item
            if (selectedEntity != null && selectedEntity.GetType() == typeof(T) && (isSelected.Invoke(item, (T)selectedEntity)))
            {
                _selectedItem = hierarchyItem;
            }

            if (getChildren != null)
            {
                var children = getChildren.Invoke(item);
                children.ForEach(x => x.Parent = hierarchyItem);
                hierarchyItem.Children = new CollectionView(children);
            }
        }

        return result;
    }
}

Listing 1

Final thoughts…

Comments are welcome on how to approve this further. My intention was to create a Type keyed dictionary of definitions that contained Func for finding the children and IComparers for deciding if the item is selected. This dictionary of definitions could then be passed in to the method that builds the tree which would make it even cleaner and better able to cope with changes in the hierarchy. However time prevented me from finalising this. Maybe later…

Downloads

WilberBeast.TreeView.Demo.zip (100.70 kb)
WilberBeast.TreeView.Demo.doc (100.70 kb)
Same as the zip version, just renamed to .doc to help with downloading.

CompositeCollection Binding Problem – It’s not part of the Visual Tree

May 31, 2011 6 comments

XAML is fantastic, but occasionally unpredictable which can cause some confusion.

One instance of this is the CompositeCollection tag which is used to build up a collection of values from a number of sources.

An example of this might be as simple as adding a “Please choose…” to the top of a drop down list or more complex scenarios, such as building up a list of products from different suppliers. In most cases, when using MVVM these kind of situations can be handled in the View Model, but even so, it can still be useful to build up lists in the XAML.

One such example I hit recently was creating a context menu for filtering on a data grid. I wanted to filter based on the values in the column, but also add two sorting options at the top of the list. A simplified version of the XAML is shown in Listing 1 below.

<ContextMenu.ItemsSource>
    <CompositeCollection>
        <MenuItem Header="Sort Ascending" />
        <MenuItem Header="Sort Descending" />
        <Separator />
        <CollectionContainer Collection="{Binding Path=FilterOptions}}" />
    </CompositeCollection>
</ContextMenu.ItemsSource>

Listing 1 – Simplified code to show an example usage of CompositeCollection

However if you try to use code such as this you’ll very quickly hit the following binding problem.

Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FilterOptions; DataItem=null; target element is ‘CollectionContainer’ (HashCode=23627591); target property is ‘Collection’ (type ‘IEnumerable’)

Why? Well it is all down to the fact that the data context of the XAML, specified at the top level that is inherited down through the elements actually goes down the Visual Tree. The killer is that the CompositeCollection, having no visual properties, is not part of the visual tree and therefore does not inherit the data context. The CompositeCollection has no clue what “FilterOptions” is in this example and thus throws a binding error.

Luckily we can easily solve this as all elements have access to the static resources of the XAML so we can easily create a bridging static resource that does the binding that we need and then use that within the composite collection. Listing 2 shows the static resource that we need in this instance.

<Window.Resources>
    <CollectionViewSource x:Key="FilterOptionsBridge" Source="{Binding Path=Filters}" />
</Window.Resources>

Listing 2 – Static resource bridging back to the data context

And finally we can adjust our CollectionContainer to point to the static resource, as in Listing 3.

...
<CollectionContainer Collection="{Binding Source={StaticResource FilterOptionsBridge}}" />
...

Listing 3 – Update to reference the static resource

As a side note, the CollectionViewSource tag needs to bind to an IEnumerable, so if you are binding to a CollectionView or one of the derived classes you’ll need to change the binding to be to the SourceCollection property as shown in Listing 4.

<Window.Resources>
    <CollectionViewSource x:Key="FilterOptionsBridge" Source="{Binding Path=Filters.SourceCollection}" />
</Window.Resources>

Listing 4 – Updated binding to reference the SourceCollection

Code Snippet – proprpc

May 26, 2011 1 comment

Anyone who has played around with WPF or Silverlight for while will have come across the INotifyPropertyChanged interface and the RaisePropertyChanged method.

In an earlier post I highlighted one possible solution, though the use of an extension method, for calling the RaisePropertyChanged method without having to use “magic strings”.

I now use this extensively in my day to day WPF work, however I still sometimes forget to include the RaisePropertyChanged call in the property setter which then takes some time to debug.

In order to avoid this I’ve finally created a code snippet that will insert a field backed property that also calls RaisePropertyChanged.

The snippet is called ‘proprpc‘ so that it is line with the other property snippets of ‘prop‘, ‘propdp‘, ‘propfull‘, etc.

Download links are given below for the .snippet file (including a zipped version) and a Visual Studio Installer file.

Extension Methods on Generics

Sometimes when I’m coding I have the “oh wouldn’t it be nice if this was possible” moments, which turn into great moments when I find to my surprise on occasion that they are.

One such moment recently was realising that I can create extension methods against generic types – something that I had never thought about before. In hindsight of course this is possible, since a specified generic type is an actual static type.

The situation I found myself in recently was whilst coding a bit of filtering code to allow the user to set up dynamic filters. As such I needed a list of comparison operators for which I created an enumerated list as per listing 1 below.

public enum ComparisonOperator
{
    EqualTo,
    NotEqualTo,
    GreaterThan,
    LessThan,
    GreaterThanOrEqualTo,
    LessThanOrEqualTo,
    StartsWith,
    EndsWith,
    Contains,
    IsEmpty,
    IsNotEmpty
}

Since most of the fields that the user could filter on would have similar comparison operators, I found myself adding in the same bunch for each filter type, i.e. a string based field would have ‘StartsWith’, ‘EndsWith’, ‘Contains’, etc.

My “oh wouldn’t it be nice if…” moment was wouldn’t it be nice if I could create an extension method to add in default sets of comparison operators to lists, and I found that I could as per the code in listing 2.

public static class ComparisonOperatorEnum
{
    public static IList AddNumericOperators(this IList comparisonOperatorList)
    {
        return new List<ComparisonOperator>()
            {
                ComparisonOperator.EqualTo,
                ComparisonOperator.IsEmpty,
                ComparisonOperator.IsNotEmpty,
                ComparisonOperator.LessThan,
                ComparisonOperator.LessThanOrEqualTo,
                ComparisonOperator.GreaterThan,
                ComparisonOperator.GreaterThanOrEqualTo,
                ComparisonOperator.NotEqualTo
            };
    }

    public static IList AddStringOperators(this IList comparisonOperatorList)
    {
        return new List<ComparisonOperator>()
            {
                ComparisonOperator.EqualTo,
                ComparisonOperator.NotEqualTo,
                ComparisonOperator.IsEmpty,
                ComparisonOperator.IsNotEmpty,
                ComparisonOperator.Contains,
                ComparisonOperator.StartsWith,
                ComparisonOperator.EndsWith
            };
    }

    public static IList AddReferenceOperators(this IList comparisonOperatorList)
    {
        return new List<ComparisonOperator>()
            {
                ComparisonOperator.EqualTo,
                ComparisonOperator.NotEqualTo,
                ComparisonOperator.IsEmpty,
                ComparisonOperator.IsNotEmpty
            };
    }

    public static IList AddBooleanOperators(this IList comparisonOperatorList)
    {
        return new List<ComparisonOperator>()
            {
                ComparisonOperator.EqualTo,
                ComparisonOperator.NotEqualTo,
                ComparisonOperator.IsEmpty,
                ComparisonOperator.IsNotEmpty
            };
    }
}

This means that my filter definition code is now shorter and clearer, and for those of you who like such things, more fluent.

myFilteredField.ComparisonOperators = new List().AddStringOperators();

It also means that if I add in any additional comparison operators in the future, then I won’t have to hunt down any filtering code and manually add them in.

A happy C# camper.

Categories: C# Tags: , ,

IQueryable, ObjectQuery and Composing LINQ to Entity Framework Queries

March 31, 2011 1 comment

As discussed in a previous post, Entity Framework and WCF work very well together, but you need to be careful about LazyLoading being switched on automatically as this can serialise the entire object graph when querying via WCF which could have a very serious impact on performance.

With LazyLoading turned off however, the problem with WCF is how to bring back all the related data that is required. The answer is to use the ObjectQuery.Include method. In order to use this with LINQ you need to cast your IQueryableto an ObjectQuery.

This additionally allows you to compose queries from logical sections and finally include the additional extra entities that will be required in the results.

using (AdventureWorksLT2008Entities context = new AdventureWorksLT2008Entities())
{
    context.ContextOptions.LazyLoadingEnabled = false;

    // simple example to select some customers
    var customersQuery = from c in context.Customers
                         where c.LastName.StartsWith("B")
                         select c;

    // additional composition of the query which could be conditional
    var customersWithOrdersQuery = from c in customersQuery
                                   where c.SalesOrderHeaders.Count > 0
                                   select c;

    // include the SalesOrderHeaders in the results
    var customerOrders = (customersWithOrdersQuery as ObjectQuery)
        .Include("SalesOrderHeaders");

    foreach (Customer c in customerOrders)
    {
        Console.WriteLine("First Name: {0}, Last Name: {1}", c.FirstName, c.LastName);
        foreach (SalesOrderHeader soh in c.SalesOrderHeaders)
        {
            Console.WriteLine("    SalesOrderID: {0}, OrderDate: {1}, TotalDue: {2}", soh.SalesOrderID, soh.OrderDate, soh.TotalDue);
        }
    }
}

Listing 1 – Example of composing queries and ObjectQuery<T>.Include

Entity Framework, LazyLoading & WCF

March 29, 2011 1 comment

Entity Framework and WCF work well together in providing a good back end service layer for a range of application types. One gotcha however that can easily catch you out without being very visible is LazyLoading.

LazyLoading defers the loading of related entities, e.g. Order for Customers, until they are accessed via a navigation property.

In the Entity Framework runtime, the default value of the LazyLoadingEnabled property in an instance of an ObjectContext is false. However, if you use the Entity Framework tools to create a new model and the corresponding generated classes, LazyLoadingEnabled is set to true in the object context’s constructor.

Thus it is possible for LazyLoading to be enabled without really explicitly requesting the feature.

There is no problem with this and LazyLoading is a great feature if you are not using WCF, however the serialisation of objects to XML before being sent over the wire causes all the navigation properties to be accessed throughout the model and thus it is very easy to accidentally serialise the whole object graph which consequently has the effect of slowing down the data access via WCF.

LazyLoading can be switched of explicitly in the ObjectContext using the code below or for Entity Framework as a whole by changing the properties of the EDMX.

public void QueryWithoutLazyLoading()
{
    using (AdventureWorksEntities context = new AdventureWorksEntities())
    {
        context.ContextOptions.LazyLoadingEnabled = false;
        ...
    }
}

Listing 1 – Disabling LazyLoading on the ObjectContext
In the next post I’ll look at how to work around not using LazyLoading with WCF as well as how to build up queries in manageable chunks that can be specialised based on logic.

WPF, MVVM and the TreeView Control using with different HierarchicalDataTemplates and DataTemplateSelector

August 24, 2010 1 comment

I spent some time today getting to grips with the TreeView control whilst trying to maintain an MVVM perspective.

To generalise the situation I have a pretty typical hierarchy of objects, e.g. Customer, Order, Product, each of which has numerous properties.

Although the objects contain the hierarchical nature within themselves, i.e. Customer has a property called Orders, the objects themselves do not contain properties useful for displaying with a TreeView (or other such hierarchical control), such as IsSelected, IsExpanded, etc.

What I want to be able to achieve is to be able to expose the objects via the ViewModel to the View so that each type of object can be displayed differently, e.g. the Customer shows a customer icon and displays the customer number and name, whereas the Order shows an order icon and displays the order number and total value. In addition I need to add the additional properties to each that will be required for use in a hierarchical control, such as the TreeView.

The options at this point are:

  • Subclass each object individually and add in the extra properties
    This means that the implementation is very much tied to this solution and is not very reusable.
  • Create a new set of new objects (one for each of the original objects), containing the additional properties required, that accept the original objects in the constructor and then exposes only the properties required for display.
    This again ties the implementation to the solution, but also limits any future changes to the view as to what can be exposed.
  • Wrap the objects in a class that has the required additional properties suitable for a hierarchy
    This is the most reusable and generic solution, but of course brings with it some additional problems.
  • Implement a pattern, such as the Decorator pattern.
    Sadly since the origin of the classes is out of my control this is not an option. This can happen when importing proxies from various WCF services, utilising classes generated by Entity Framework, etc.

I opted for the third option, creating a wrapper, which makes life a little harder, i.e. is it not a quick and dirty solution, but it has the advantage of reuse.


The Hierarchy Item Wrapper (HierarchyItemViewModel)

The first item we will create here is the wrapper for the objects to be shown in the TreeView. I’ll call this ‘HierarchyItemViewModel’.

In my implementation this inherits from ViewModelBase. ViewModelBase simply sets up some of the key points required in an MVVM solution, such as ObservableObjects. See the MVVM Foundation for a good starting point.

The main points in the code shown below in Listing 1 are:

  • The constructor accepts an object which is the data item being wrapped. This is then exposed to the View via the DataItem property.
  • A CollectionView of Children is exposed as a property as well as Parent.
  • The IsSelected and IsExpanded properties that we needed are created.
  • The properties call the RaisePropertyChanged method on which I have written about previously.
public class HierarchyItemViewModel : ViewModelBase
{
    private CollectionView _children;
    private bool _isExpanded;
    private bool _isSelected;

    public HierarchyItemViewModel(object dataItem)
    {
        DataItem = dataItem;
    }

    public object DataItem { get; private set; }

    public HierarchyItemViewModel Parent { get; set; }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            _isExpanded = value;
            RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
        }
    }

    public System.Windows.Data.CollectionView Children
    {
        get { return _children; }
        set { _children = value; }
    }

}

Listing 1 – HierarchyItemViewModel

The Hierarchy View Model (HierarchyViewModel)

Now we have our wrapper for the items we need to create our nested set of items ready to expose to the actual TreeView.

Listing 2, below, shows the code that builds the hierarchy taking in a list of Customer objects in the constructor. We are assuming that we have already obtained from elsewhere the actual data we want to display. The code is a bit long winded to keep it simple. For a more complex but more generic version see this post.

So here are we are going to wrap each item in a HierarchyItemViewModel object and create the parent and child relationships.

In addition, since we actually want to select a certain item from the list and make sure that it is visible we look out for our chosen item, identified in the constructor, which in this case I have called selectedEntity.

public class HierarchyViewModel : ViewModelBase
{
    public CollectionView Customers { get; private set; }
    private HierarchyItemViewModel _selectedItem;

    public HierarchyViewModel(List customers, object selectedEntity)
    {
        // create the top level collectionview for the customers
        var customerHierarchyItemsList = new List();

        foreach (Customer c in customers)
        {
            // create the hierarchy item and add to the list
            var customerHierarchyItem = new HierarchyItemViewModel(c);
            customerHierarchyItemsList.Add(customerHierarchyItem);

            // check if this is the selected item
            if (selectedEntity != null && selectedEntity.GetType() == typeof(Customer) && (selectedEntity as Customer).Equals(c))
            {
                _selectedItem = customerHierarchyItem;
            }

            // if there are any orders in customerHierarchyItem
            if (c.Orders.Count != 0)
            {
                // create a new list of HierarchyItems
                var orderHierarchyItemsList = new List();
                // loop through the orders and add them
                foreach (Order o in c.Orders)
                {
                    // create the hierarchy item and add to the list
                    var orderHierarchyItem = new HierarchyItemViewModel(o);
                    orderHierarchyItem.Parent = customerHierarchyItem;
                    orderHierarchyItemsList.Add(orderHierarchyItem);

                    // check if this is the selected item
                    if (selectedEntity != null && selectedEntity.GetType() == typeof(Order) && (selectedEntity as Order).Equals(o))
                    {
                        _selectedItem = orderHierarchyItem;
                    }

                    // if there are any products in orderHierarchyItem
                    if (o.Products.Count != 0)
                    {
                        // create a new list of HierarchyItems
                        var productHierarchyItemsList = new List();
                        // loop through the sites and add them
                        foreach (Product p in o.Products)
                        {
                            // create the hierarchy item and add to the list
                            var productHierarchyItem = new HierarchyItemViewModel(p);
                            productHierarchyItem.Parent = orderHierarchyItem;
                            productHierarchyItemsList.Add(productHierarchyItem);

                            // check if this is the selected item
                            if (selectedEntity != null && selectedEntity.GetType() == typeof(Product) && (selectedEntity as Product).Equals(p))
                            {
                                _selectedItem = productHierarchyItem;
                            }
                        }

                        // create the children of the order
                        orderHierarchyItem.Children = new CollectionView(productHierarchyItemsList);
                    }
                }
                // create the children of the customer
                customerHierarchyItem.Children = new CollectionView(orderHierarchyItemsList);
            }
        }

        this.Customers = new CollectionView(customerHierarchyItemsList);

        // select the selected item and expand it's parents
        if (_selectedItem != null)
        {
            _selectedItem.IsSelected = true;
            HierarchyItemViewModel current = _selectedItem.Parent;

            while (current != null)
            {
                current.IsExpanded = true;
                current = current.Parent;
            }
        }
    }
}

Listing 2 – HierarchyViewModel

The TreeView XAML

The next step is to create our TreeView in XAML and bind it to our HierarchyViewModel. For the simplicity of this example I’ve added the TreeView class straight to the MainWindowView. This could of course be wrapped up into its own UserControl. The ViewModel is attached to the DataContext of the View on creation. I won’t go into the code for how to bind the ViewModel to the View as this is covered in depth elsewhere. Important points to note in the code in Listing 3 are:

  • The TreeView tag (line 11) where the DataContext is set for the TreeView, which identifies from where the data for the TreeView will be sourced.
  • The three HierarchicalDataTemplate items, one for each of Customer, Order and Product. Note that each binds to different properties within the DataItem and each could have its own styling. This is the key point of this example.
  • The Window.Resources (line 8) where the HierarchyDataTemplateSelector is identified. This essentially provides a key which can be used in the XAML to a method that selects which HierarchicalDataTemplate will be used for each item in the TreeView. I’ll cover this in more depth below,
  • Again, in the TreeView tag (line 11) the ItemTemplateSelector which references the hierarchyDataTemplateSelector mentioned above.
<Window x:Class="WilberBeast.TreeView.Demo.Views.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ViewModels="clr-namespace:WilberBeast.TreeView.Demo.ViewModels"
        xmlns:View.Helper="clr-namespace:WilberBeast.TreeView.Demo.Views.Helper"
        Title="MainWindowView" Height="350" Width="525">
    <Window.Resources>
        HierarchyDataTemplateSelector x:Key="hierarchyDataTemplateSelector" />
    </Window.Resources>
    <Grid>
        <TreeView Name="HierarchyTreeView" DataContext="{Binding Path=HierarchyViewModel}" ItemTemplateSelector="{StaticResource hierarchyDataTemplateSelector}" ItemsSource="{Binding Customers}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
                    <Setter Property="IsSelected" Value="{Binding IsSelected}" />
                    <Setter Property="FontWeight" Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.Resources>
                <HierarchicalDataTemplate x:Key="CustomerTemplate" DataType="{x:Type ViewModels:HierarchyItemViewModel}" ItemsSource="{Binding Path=Children}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=DataItem.Name}" Margin="0 0 5 0"/>
                        <TextBlock Text="{Binding Path=DataItem.Number}"/>
                    <!--<span class="hiddenSpellError" pre=""-->StackPanel>
                <!--<span class="hiddenSpellError" pre=""-->HierarchicalDataTemplate>
                OrderTemplate" DataType="{x:Type ViewModels:HierarchyItemViewModel}" ItemsSource="{Binding Path=Children}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=DataItem.Number}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
                ProductTemplate" DataType="{x:Type ViewModels:HierarchyItemViewModel}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=DataItem.Name}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

Listing 3 – TreeView XAML

The DataTemplateSelector

Since to the TreeView class the all the objects within the TreeView appear to be of the same type, due to each being wrapped up in the HierarchyItemViewModel class, in order to display the Customer, Order and Product objects with different styles and content we have to have some code to help the TreeView identify which HierarchicalDataTemplate to use in each case. This is where the TemplateSelector comes in. This is nothing new or fancy, just one of the those hidden gems of WPF. The code for the HierarchyDataTemplateSelector is shown in Listing 4below. The code is fairly self explanatory. Basically the class inherits from the base class DataTemplateSelector and overrides the virtual method SelectTemplate. The TreeView passes the items one at a time to this method and the return value is simply the name of the HierarchicalDataTemplate to use.

public class HierarchyDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate retval = null;
        FrameworkElement element = container as FrameworkElement;

        if (element != null && item != null && item is HierarchyItemViewModel)
        {
            HierarchyItemViewModel hierarchyItem = item as HierarchyItemViewModel;
            if (hierarchyItem.DataItem != null)
            {

                if (hierarchyItem.DataItem.GetType() == typeof(Customer))
                {
                    retval = element.FindResource("CustomerTemplate") as DataTemplate;
                }

                else if (hierarchyItem.DataItem.GetType() == typeof(Order))
                {
                    retval = element.FindResource("OrderTemplate") as DataTemplate;
                }

                else if (hierarchyItem.DataItem.GetType() == typeof(Product))
                {
                    retval = element.FindResource("ProductTemplate") as DataTemplate;
                }
            }
        }

        return retval;
    }
}

Listing 4 – HierarchyDataTemplateSelector

All the code used in this example has been pulled together into one downloadable project that demonstrates the principle. The links are below.

Please do send me your comments as they are always welcome.

Happy coding…

WilberBeast.TreeView.Demo.zip (100.70 kb)
WilberBeast.TreeView.Demo.doc (100.70 kb)
Same as the zip version, just renamed to .doc to help with downloading.

WPF, MVVM and RaisePropertyChanged

July 21, 2010 2 comments

Several times recently during development I have come across situations where specific strings are required for functionality to work effectively and yet not having the correct string will not cause any compilation or run time errors, features just won’t work. The features may be subtle enough such that it could be some time before any break in functionality is noticed and therefore could reach production code. In coding terms these are called “magic strings” and are something to be avoided at all costs.

One example of this I have come across often in MVVM WPF or Silverlight projects where the ViewModels implement the INotifyPropertyChanged interface such that when a property is changed it is common to see code such as the following.

private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set
    {
        if (_firstName != value)
        {
            _firstName = value;
            RaisePropertyChanged("FirstName");
        }
    }
}

The alarm bell for me here is the hard coded name of the property “FirstName” within the RaisePropertyChanged method. In this simple example it is clear, but in more complex code it can easily get lost and also magic strings such as these won’t be picked up and adjusted in any automated refactoring of the names of the properties.

You can obtain the name of the property using the following bit of code, however it includes either ‘get_’ or ‘set_’ at the start depending upon where it is called.

MethodBase.GetCurrentMethod().Name;

Thus I’ve created the following extension method to take the property name and simply strim off the first 4 characters thus leaving you with the correct property name.

public static string GetPropertyName(this MethodBase methodBase)
{
    return methodBase.Name.Substring(4);
}

Using this extension method, as below, it means that you will be able to raise property changed events without concern that in future your property name might change.

RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());

Update: I’ve now created a Visual Studio code snippet that is used for creating field backed properties that automatically includes the “RaisePropertyChanged” call which can be found here.