Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static verification of bindings

Tags:

binding

wpf

Or "how do you make sure all your bindings stay correct?"
(this is kinda lengthy, but bear with me, I tried to make it as short as I could)

Consider the following example:

    <TextBox Name="tb" />
    <TextBlock Text="{Binding Text.TheProp, ElementName=tb}" />

It is perfectly known at compile time that the binding is incorrect (i.e. the parser knows the type of element tb, and therefore, it knows the type of it's Text property, and therefore, it knows that TheProp doesn't exist).
Yet, this code will compile and run (although with a binding error message in debug output).

This behavior may come in very handy in some situations: no matter what exact type my data is, as long as it has appropriately named properties, I'm ok. Thus, we get sort of "declarative duck typing".

However, duck typing is not always a good thing.
Specifically, while using the MVVM pattern, I know (most of the time) the exact types of all my ViewModel objects. On the other hand, the models become more and more complex over time, which gets me worried about future refactoring: what if I decide to rename some properties, or, God forbid, put them in a separate aggregated object? What's going to happen with all my bindings then? Will I have to rake all XAML files by hand? And even without refactoring - what if I simply make a typo?

A similar problem is already solved in other places of XAML. If, for instance, you put an incorrect property name in Style/Setter/@Property, you get a compile time error.
TemplateBinding also provides such verification. Which is very handy.

So, ideally, I would love to see something like this:

ProductViewModel.cs:

    public class ProductViewModel
    {
        public Name { get; set; }
        public Price { get; set; }
    }

ProductView.XAML:

    <UserControl x:Class="Shopping.View.ProductView"
                 x:DataContextType="vm:ProductViewModel"
                 xmlns:vm="clr-namespace:Shopping.ViewModel"
                 ... >
        <TextBox Text="{Binding Name}" />  <!-- OK -->
        <TextBox Text="{Binding Price}" /> <!-- OK -->
        <TextBox Text="{Binding ABC}" />   <!-- Compile time error: there is no property ABC in ProductViewModel -->
    </UserControl>

ShoppingCart.XAML:

    <UserControl x:Class="Shopping.View.ShoppingCartView"
                 x:DataContextType="vm:ShoppingCartViewModel"
                 xmlns:vm="clr-namespace:Shopping.ViewModel"
                 ... >
        <ItemsControl ItemsSource="{Binding Products}"
                      ItemType="vm:ProductViewModel" >  <!-- Static check happens here 
                                                             ShoppingCartViewModel.Products must 
                                                             implement IEnumerable<ProductViewModel> -->
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="vm:ProductViewModel">
                    <view:ProductView /> <!-- DataContext is known to be of correct type
                                              because of DataTemplate.DataType property -->
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </UserControl>

But let's get back to reality. In reality, all that dreaming is just not going to happen in the near future.

However, I am sure I'm not the first person to have this problem.
So, finally, the question is: How do you make sure your bindings are correct? And that they stay that way?

like image 244
Fyodor Soikin Avatar asked Sep 04 '10 14:09

Fyodor Soikin


1 Answers

How about static analysis of your Xaml performed as a post-build step?

As part of .Net 4, Microsoft released a new System.Xaml library to provide robust Xaml parsing and serialization support independent of WPF. They are now beginning to build all kinds of interesting things on top of it, some of which may help you out.

In the XamlToolkit, for example, you'll find the XamlDOM that enables you to do easy static analysis of Xaml files. And taking that a bit further, there's FxCop rules for XAML.

Of most interest is Rob Relyea's BindingFinder that has the explicit goal of type checking Bindings in Xaml. This requires that you have type hints in your Xaml, like the DataType attribute in a DataTemplate, or the the new d:DataContext attribute on your Views (which Blend uses to provide design-time data). It then uses the XamlDOM to check that everything matches up.

Update: Resharper 6 now provides intellisense for data bindings, and warnings if you get your property paths wrong.

like image 166
Samuel Jack Avatar answered Oct 04 '22 16:10

Samuel Jack