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?