Contentpresenter,基于类型的datatemplate选择和绑定

我有一个ItemsControl绑定到项目列表。 这些项目具有名称和值属性。 value属性的类型为Object,以允许使用不同的数据类型。 要正确显示value属性,我可以为我可能使用的每种数据类型使用带有datatemplate的ContentPresenter。

                               

ContentPresenter使用正确的数据类型并且运行良好。 我的问题是编辑这些值对绑定项没有任何影响。 我怀疑这是因为我绑定到ContentPresenter的content属性而不是直接绑定到Value。 我尝试过像这样使用ContentPresenter:

      

但是这样就没有选择正确的DataTemplate,它只是显示Object而不是String。 我也试图在DataTemplate的绑定中省略这样的路径:

     

有了这个,我得到一个exception,告诉我使用Path或XPath属性。

所以我的问题是:如何正确绑定到Value,以便使用正确的DataTemplate显示,并且任何值的编辑都将应用于绑定项。

顺便说一句,由于某种原因,我的问题格式化的代码块在第一行后缩进了很多。 我试着修理它,但我不明白发生了什么。

我想你会从阅读有关DataTemplate的内容中受益。 首先,我建议您长时间阅读MSDN上的数据模板概述页面。 正如我在评论中提到的,您不应该在DataTemplate使用ContentPresenter 。 从链接页面:

您通常使用ContentControl的ControlTemplate中的ContentPresenter来指定要添加内容的位置

似乎缺少的是数据如何以及从DataTemplate 内部绑定到什么内容。 DataTemplateDataContext将自动设置为DataType属性中指定的类型的实例。 因此, DataTemplate可以访问的属性也将取决于DataType属性中指定的DataType 。 例如,您不能这样做,因为string没有Value属性。

    

相反,对于string ,您需要将数据绑定到整个DataContext值,如下所示:

    

或者,如果您有一个类名SomeClass并且该类具有Value属性, 那么您可以这样做:

    

现在,因为已经定义了这些DataTemplate而没有设置它们的x:Key值,所以只要框架看到相关类型的对象(并且没有设置其他显式模板),它就会自动呈现每个DataTemplate的内容。 所以试试这个,如果你还有问题,请告诉我。

我找到了解决这个问题的方法。 绑定不起作用的原因是因为我绑定了ContentControl的内容。 对绑定源的双向绑定不起作用,如此处所述。 这就是我得到例外的原因。 我仍然使用ContentControl和DataTemplates来区分数据类型。 但是,不是绑定到ContentControl的内容,而是绑定到ContentControl绑定的值。 注意绑定中的Path。

                 

这是问题的解决方案。 我只是感觉有点不舒服使用ContentControl只是为了区分DataTypes和不合逻辑的绑定。

另外,谢谢你帮我解开这个问题Sheridan。

我已经对我的解决方案感到不舒服,我还遇到了无法向DataTemplates添加List DataType的问题。 我最终使用了一个DataTemplateSelector,它产生了更好的代码。 这里是:

ContentControl。 DataTemplate应用于的数据的容器:

   

一些DataTemplates和DataTemplateSelector的声明:

          ... 

DataTemplateSelector的代码:

  public class PropertyTemplateSelector : DataTemplateSelector { public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) { DataTemplate template = null; IPropertyItem propertyItem = item as IPropertyItem; if (propertyItem != null) { FrameworkElement element = container as FrameworkElement; if (element != null) { var value = propertyItem.Value; if (value is String) { template = element.FindResource("dtStringValue") as DataTemplate; } else if (value is Int32) { template = element.FindResource("dtIntegerValue") as DataTemplate; } ....