所以我想知道的是:为什么微软至少不给我们提供一种选项,可以获得强类型数据绑定:就像在VB6中,如果我们真的想自虐,可以将任何对象都变成一个variant,但大多数情况下使用普通类型的变量更有意义。微软难道不能这样做吗?
这是一个例子,如果C#中的属性"UsrID"不存在,您将从Intellisense获得警告,并且如果尝试此操作,则会从编译器获得错误提示。
string userID = myUser.UsrID;
但是在XAML中,您可以随心所欲地进行这些操作:
<TextBlock Text="{Binding UsrID}" />
Intellisense、编译器和应用本身在运行时都不会给你任何提示,表明你做错了什么。尽管这只是一个简单的例子,但任何处理复杂对象图和复杂 UI 的实际应用程序都会有很多类似的场景,这些场景并不简单,也不容易进行故障排除。即使第一次正确地实现了它,如果重构代码并更改了 C# 属性名称,则问题就来了。一切都将编译,并且没有错误,但什么也不起作用,你只能费力搜寻整个应用程序,试图找出哪里出了问题。
我的一个可能的建议(只是脑海中的想法,我还没有深思熟虑)可能是这样的:
对于逻辑树的任何部分,您可以在 XAML 中指定它所期望的对象的 DataType,如下所示:
<Grid x:Name="personGrid" BindingDataType="{x:Type collections:ObservableCollection x:TypeArgument={data:Person}}">
这可能会在 .g.cs 文件中生成一个强类型的 ObservableCollection<Person> TypedDataContext 属性。因此,在您的代码中:
// This would work
personGrid.TypedDataContext = new ObservableCollection<Person>();
// This would trigger a design-time and compile-time error
personGrid.TypedDataContext = new ObservableCollection<Order>();
如果您通过网格上的控件访问那个 TypedDataContext,它将知道您正在尝试访问哪种类型的对象。
<!-- 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>
我写了一篇博客文章(在这里),更详细地解释了我对WPF / XAML数据绑定的挫败感,并提出了一个显著更好的方法。有没有什么理由它不能起作用?是否有人知道微软是否计划修复这个问题(按照我的建议,或者希望是更好的建议)?
string userID = myUser.UsrID;
但是如果我想在 XAML 中做同样的事情,(a) 它不会给我任何 IntelliSense 提示表明我做错了;(b) 当我编译我的应用程序时,它不会告诉我我正在做错;并且 (c) 最令人惊讶的是,即使当我运行我的应用程序时,它也不会告诉我我正在做错。它只是静默地失败。
- Ken Smith