views:

985

answers:

7

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.

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)?

+6  A: 

There will be IntelliSense support for data-binding in Visual Studio 2010. That seems to be what your complaint really boils down to, since data-binding is strongly-typed. You just don't find out until run-time whether or not the binding succeeded, and more often than not it fails quietly rather than with a noisy exception. When a binding fails, WPF dumps explanatory text via debug traces, which you can see in the Visual Studio output window.

Besides the lack of IntelliSense support and a few weird syntax issues, data-binding is quite well done (at least in my opinion). For some more assistance debugging data-bindings, I would check out Bea's lovely article here.

Charlie
I haven't played with VS 2010 yet, but do you know how that will work? I haven't read anything that indicates that it will solve the problem I outline above, namely, that it'll force me to declare the type of the object that I want to bind to, and then tell me when I bind to it inappropriately. But like I said, I haven't played with it yet.
Ken Smith
BTW, I've read Bea's article many times: it's the only way I've survived so far :-). But my point is that the approaches Bea outlines *shouldn't be needed*. If DataBinding is done correctly, all of that troubleshooting work should be done by the compiler and IDE, not by the developer.
Ken Smith
I respectfully disagree. Haven't you seen Spiderman? "With great power comes great responsibility." A feature as powerful as data-binding is going to require a lot of hardship to become fluent with. But it is because data-binding is so flexible and can do so much for you that it is often difficult to debug.
Charlie
Maybe this is where you and I will disagree. I never used the Variant datatype back in VB6, because it was bad practice -- however much power it might have given me to assign variables willy-nilly. One of the indispensable characteristics of a well-designed language is precisely what it *won't* let me do. If what I'm doing is gonna screw up, I'd much rather have the compiler tell me that than my users.
Ken Smith
+1  A: 

It sounds like what you are asking for would not require any framework changes, and possibly is already fixed in VS 2010 (I don't have it installed).

The XAML designer needs IntelliSense for bindings within a DataTemplate when you specify a DataType, which is already possible like so:

<DataTemplate DataType="{x:Type data:Person}">
...
</DataTemplate>

I agree that having IntelliSense in this case would be a helpful change, but your other suggestions seem to miss the point of being able to change DataContexts at runtime and use DataTemplates for different types to render them uniquely.

Bryce Kahle
Well said. I agree with this summary 100%.
Anderson Imes
OK, good point about the DataTemplates. I agree that this is a valuable scenario. But there are lots of times when using separate datatemplates and selecting between them at runtime is overkill for what I need. And in those scenarios, I still think it would be valuable to be able to declare my type at *some* level in the XAML tree. If I'm designing my form to only work with one Type, I'd like to be able to specify that in the XAML, so that I can know immediately and clearly when I've mucked up.
Ken Smith
A: 

Also, if you have your output window open when you're debugging your project, VS will inform you of any databinding errors, i.e. that the property a Control is bound to doesn't exist.

This is true -- though I'm distinctly of the opinion that it should throw an exception, rather than merely print a debug error. However, I've found a number of other scenarios where WPF encounters fatal binding errors, and fails silently, without even printing a debug message (unless you go through the hoops of enabling verbose tracing). Bad default! Bad default! No biscuit! :-)
Ken Smith
A: 

Ken, C# would benefit from a concise syntactical element for referencing a PropertyInfo class. PropertyInfo structures are static objects defined at compile time and as such provide a unique key for every Property on an object. Properties could then be validated at compile time.

The only problem with this is the weirdness of treating an instance of a object as a data type given that strong typing is enforced on types, not the values of a type. Traditionally, compilers don't enforce data values, and instead rely on runtime code to check its data. Most cases its not even possible to validate data at compile time, but reflection is one of those edge cases where it is at least possible.

Alternatively, the compiler could create a new data type for every property. I could imagine a lot of types being created, but that would enable compile time enforcement of property binding.

One way to think about it is that the CLR introduced a level of reflection that was another level of magnitude compared to the systems that preceded it. It's now being used to do some rather impressive stuff like data binding. But its implementation is still at a metadata level, a kind of report from the compiler for every data type is generates. I supposed one way to grow C# would be to promote the metadata to compile time checking.

It seems to me that someone could develop a compilation tool that adds that reflection level validation. The new intellisense is sorta like that. It would be tricky to generically discover string parameters that are destined to be compared to PropertyInfos, but its not impossible. A new data type like "PropertyString" could be defined that clearly identifies parameters that will be compared to PropertyInfos in the future.

Anyway, I feel your pain. I've chased down a lot of misspelled property name references. Honestly, there are a lot of irritations in WPF related to reflection. A useful utility would be a WPF enforcement checker that makes sure all your static control constructors are in place, your attributes properly defined, bindings are accurate, correct keys, etc. There is a long list of validations that could be performed.

If I were still working for Microsoft, I'd probably try doing it.

Thanks for feeling my pain, Grant. Nobody else here seems to understand why I think the MS implementation is problematic, so I was feeling lonely. Other opinions notwithstanding, I remain convinced that XAML databinding is badly broken. A classic example that I ran into recently comes when you're trying to re-merge branches. It's pretty difficult to muck up a branch merge in C# without the compiler complaining. But if the underlying data types have changed, you won't know your XAML is broken until you do a full QA pass: even automated tests won't typically catch these errors.
Ken Smith
+1  A: 

Abso-effing-lutely! This is my biggest gripe with XAML! Not having the compiler enforce valid databindings is a BIG issue. I don't really care about intellisense, but I DO care about the lack of refactoring support.

Changing property names or types is dangerous in a WPF application - using the built in refactoring support won't update data bindings in XAML. Doing a search and replace on the name is dangerous as it may change code that you didn't intend to change. Going through a list of find results is a pain in the arse and time consuming.

MVC has had strongly typed views for some time - the MVC contrib project provided them for MVC1 and MVC2 provides them natively. XAML must support this in future, particularly if it is used in "agile" projects where an application's design evolves over time. I haven't looked at .NET 4.0 / VS2010, but I hope the experience is far better than it is!

Dale Anderson
+1  A: 

I feel that xaml is sth like old-days html. i cannot imagine that after 10+ years, i am doing programming in that way: typing open-close tags manually because i cannot have a matured GUi for me to define styles and binding and templates. I strongly support your view, Ken. I feel very weird why so many people are supporting MVVM without a single complain about the pain in debugging xaml. Command binding and data binding are very good concepts and I have been designing my winform apps in that way. However, the xaml binding solution together with some other xaml issue (or lack of a sophisticated feature) is really a big failure in VS. It made the development and debug very difficult, and made the code very unreadable.

fluxray
A: 

I wrote a proof-of-concept program that verifies data bindings in XAML and posted it on my blog here.

I don't have the free time to make it into a usable tool at the moment - so if anyone here wants to take the code and make a full featured tool you're welcome.

Nir