One of my biggest pet peeves with how databinding works with XAML is that there's no option to strongly type your databindings. In other words, in C#, if you want to access a property on an object that doesn't exist, you won't get any help from Intellisense, and if you insist on ignoring Intellisense, the compiler will gripe at you and won't let you proceed -- and I suspect that lots of folks here would agree that this is a Very Good Thing. But in XAML databinding, you're operating without a net. You can bind to anything, even if it doesn't exist. Indeed, given the bizarre syntax of XAML databinding, and given my own experience, it's a great deal more complicated to bind to something that does exist than to something that doesn't. I'm much more likely to get my databinding syntax wrong than to get it right; and the comparative time I spend troubleshooting XAML databindings easily dwarfs the time I spend with any other portion of Microsoft's stack (including the awkward and annoying WCF, if you can believe it). And most of that (not all of it) goes back to the fact that without strongly-typed databindings, I can't get any help from either Intellisense or the compiler.
So what I want to know is: why doesn't MS at least give us an option to have strongly-typed databindings: kind of like how in VB6, we could make any object a variant if we were really masochistic, but most of the time it made sense to use normal, typed variables. Is there any reason why MS couldn't do that?
Here's an example of what I mean. In C#, if the property "UsrID" doesn't exist, you'll get a warning from Intellisense and an error from the compiler if you try this:
string userID = myUser.UsrID;
However, in XAML, you can do this all you want:
<TextBlock Text="{Binding UsrID}" />
And neither Intellisense, the compiler, or (most astonishingly) the application itself at runtime will give you any hint that you've done something wrong. Now, this is a simplistic example, but any real-world application that deals with complex object graphs and complex UI's is going to have plenty of equivalent scenarios that aren't simple at all, nor simple to troubleshoot. And even after you've gotten it working correctly the first time, you're SOL if you refactor your code and change your C# property names. Everything will compile, and it'll run without an error, but nothing will work, leaving you to hunt and peck your way through the entire application, trying to figure out what's broken.
One possible suggestion (off the top of my head, and which I haven't thought through) would maybe be something like this:
For any portion of the logical tree, you could specify in XAML the DataType of the object that it's expecting, like so:
<Grid x:Name="personGrid" BindingDataType="{x:Type collections:ObservableCollection x:TypeArgument={data:Person}}">
This would perhaps generate a strongly-typed ObservableCollection<Person> TypedDataContext property in the .g.cs file. So in your code:
// This would work
personGrid.TypedDataContext = new ObservableCollection<Person>();
// This would trigger a design-time and compile-time error
personGrid.TypedDataContext = new ObservableCollection<Order>();
And if you then accessed that TypedDataContext through a control on the grid, it would know what sort of an object you were trying to access.
<!-- It knows that individual items resolve to a data:Person -->
<ListBox ItemsSource="{TypedBinding}">
<ListBox.ItemTemplate>
<DataTemplate>
<!--This would work -->
<TextBlock Text="{TypedBinding Path=Address.City}" />
<!-- This would trigger a design-time warning and compile-time error, since it has the path wrong -->
<TextBlock Text="{TypedBinding Path=Person.Address.City} />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've made a blog posting here that explains more about my frustrations with WPF/XAML databinding, and what I think would be a significantly better approach. Is there any reason why this couldn't work? And does anyone know if MS is planning to fix this problem (along the lines of my proposal, or hopefully, a better one)?