Archive

Posts Tagged ‘Generics’

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.

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: , ,