WPF / Silverlight / XAML中的强类型数据绑定?

WPF / Silverlight / XAML中的强类型数据绑定?

问题描述:

我最大的宠物小狗之一,如何使用XAML进行数据绑定是没有任何选择来强烈地键入数据绑定。换句话说,在C#中,如果要访问不存在的对象上的属性,则不会从Intellisense得到任何帮助,如果您坚持忽略Intellisense,编译器将会抓住您并赢得让你继续 - 我怀疑这里的很多人都会同意这是一个非常好的事情。但是,在XAML数据绑定中,您正在运行没有网络。即使不存在,也可以绑定到任何。实际上,考虑到XAML数据绑定的奇怪语法,并给出了我自己的经验,绑定到存在的东西比不存在的东西要复杂得多。我更有可能使我的数据绑定语法错误,而不是正确;而我花费在XAML数据库中排除故障的比较时间容易使我与微软堆栈的任何其他部分(包括尴尬和令人讨厌的WCF,如果你能相信)花费的时间相差无几。而且大部分(并不是全部)回到了没有强类型数据绑定的事实,我无法从Intellisense或编译器获得任何帮助。

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.

所以我想知道的是:为什么MS至少给我们一个选项有强类型的数据绑定:有点像VB6中的一样,如果我们真的很疯狂,但大多数时候使用正常类型的变量是有意义的。有没有什么原因MS不能这样做?

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?

这是一个我的意思的例子。在C#中,如果属性UsrID不存在,您会收到Intellisense的警告和编译器的错误,如果您尝试这样做:

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;

但是,在XAML中,您可以这样做:

However, in XAML, you can do this all you want:

<TextBlock Text="{Binding UsrID}" />

在运行时,Intellisense,编译器或(最惊人的)应用程序本身都不会给你任何提示你做错了事情。现在,这是一个简单的例子,但是处理复杂对象图和复杂UI的任何真实应用程序都将具有很多等同的场景,这些方案根本不简单,也不易于排除故障。即使您已经第一次正常工作,您也是SOL,如果您重构代码并更改C#属性名称。一切都将编译,它会运行没有错误,但没有任何工作,让您通过整个应用程序狩猎和啄钻,试图弄清楚是什么。

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:

对于逻辑树,您可以在XAML中指定它期望的对象的DataType,如下所示:

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}}">

这可能会生成一个强类型的ObservableCollection< Person> .g.cs文件中的TypedDataContext属性。所以在你的代码中:

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>(); 

如果您通过网格上的控件访问该TypedDataContext,它会知道什么样的

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

Ken,C#将从引用PropertyInfo类的简洁语法元素中受益PropertyInfo结构是在编译时定义的静态对象,因此提供了一个独特的关键在于对象上的每个属性,然后可以在编译时验证属性。

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.

考虑这一点的一个方法是CLR引入了与之前的系统相比的另一个重要程度。它现在被用来做一些令人印象深刻的东西,如数据绑定。但是它的实现仍然在元数据级别,从编译器为每种数据类型生成一种报告。我应该有一种方式来增长C#将是促进元数据来编译时间检查。

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.

在我看来,有人可以开发一个编译工具来增加反射级验证。新的智慧是这样的。一般来说,发现要与PropertyInfos进行比较的字符串参数是非常棘手的,但这不是不可能的。可以定义一个新的数据类型,如PropertyString,可以清楚地识别将来与PropertyInfos进行比较的参数。

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.

无论如何,我感到你的痛苦。我追逐了很多拼错的物业名称参考。老实说,WPF中有很多与反射有关的刺激。一个有用的实用程序将是一个WPF执行检查器,可以确保所有的静态控制构造函数都到位,属性被正确定义,绑定是准确的,正确的键等。可以执行很长的验证列表。

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.

如果我还在为Microsoft工作,我可能会尝试这样做。

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