Logo

NHibernate

The object-relational mapper for .NET

NHibernate and WPF: Test Databinding with Caliburn

As I said before, for the Chinook Media Manager I’m not using neither Caliburn nor Prism.
But, whenever I found a limitation on the current tools, I start looking a solution elsewhere. This is how I meet Caliburn.Testability, a great tool.

The problem

We don’t know what would be the ViewModel for the View at design time. This is the reason why we don’t have intelliscence in XAML, and in general our databinding are not strongly typed in XAML. So, we can write “naem” instead of “Name”.

The solution

Caliburn has a great tool named “Caliburn Testability”, you can read the full post here. As Rob Eisenberg said, I take this one step farther to build an automatic test.

This is the code:

public class DataBindingValidator
{
    private static BindingValidator ValidatorFor(
            Type guiElement, Type presenterType)
    {
        var boundType = new BoundType(presenterType);
        var instance = (DependencyObject)Activator.CreateInstance(guiElement);
        IElement element = Bound.DependencyObject(instance, boundType);
        return new BindingValidator(element);
    }

    /// <summary>
    /// Validate the bindings of a keyvalue pair 
    /// where the key is the View type and the 
    /// value is the ViewModel type.
    /// </summary>
    public IEnumerable<ValidationResult>
            Validate(IDictionary<Type, Type> viewViewModelDictionary)
    {
        foreach (var viewViewModel in viewViewModelDictionary)
        {
            BindingValidator validator
                = ValidatorFor(viewViewModel.Key, viewViewModel.Value);
            ValidationResult validatorResult = validator.Validate();
            yield return validatorResult;
        }
    }
}

This class validate a IDictionary<Type, Type>, the key is the “View” type, and the value is the ViewModel type. The View need to have a public constructor without args, this test will create an instance of the View. The ViewModel type could be a class, could be abstract and even an interface!

The test is really easy, if you are using Caliburn, you already have a IViewStrategy. The Chinook Media Manager use a convention based approach and I don’t have an special artifact for this purpose. So my test looks as follows:

 

[TestFixture]
public class TestDataBindings
{
    private static Type GetViewForViewModel(Type viewModelType)
    {
        string viewName = viewModelType.Name.Replace("ViewModel", "View");
        string viewFullName = string.Format("ChinookMediaManager.GUI.Views.{0}, ChinookMediaManager.GUI", viewName);
        Type viewType = Type.GetType(viewFullName, true);
        return viewType;
    }

    [Test]
    public void AllDatabindingsAreOkay()
    {
        bool fail = false;
        var databindingValidator = new DataBindingValidator();

        Type examplePresenterType = typeof(AlbumManagerViewModel);

        var dictionary = examplePresenterType.Assembly.GetTypes()
                                            .Where(type => type.Namespace.EndsWith("ViewModels"))
                                            .ToDictionary(vmType => GetViewForViewModel(vmType), vmType => vmType);

        

        foreach (var validationResult in databindingValidator.Validate(dictionary))
        {
            if(validationResult.HasErrors)
            {
                Console.WriteLine(validationResult.ErrorSummary);
                fail = true;
            }
        }

        fail.Should().Be.False();
    }
}

If you have any error in your databinding this test will fail. This test also show you a list of the DataBinding errors in the console, and for each error the full path inside the View:

image

You can see here the “nesting level”, Album is a property of the EditAlbumViewModel, Title is a property in the Album type. Titlo doesn’t exist. EditAlbumView.Grid.TextBox is the full xaml path to the control holding the databinding. It show Grid and TextBox because these elements doesn’t have a name in xaml.

This is why I use Caliburn.Testability in Chinook Media Manager.


Posted Sun, 15 November 2009 06:42:25 AM by jfromainello
Filed under: NHibernate, WPF

comments powered by Disqus
© NHibernate Community 2024