Archive

Archive for June, 2011

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.