内容presenter基于类型的DataTemplate选择和绑定
我有结合的项目列表一个ItemsControl。这些项目有一个名字和值属性。 value属性的类型是Object,以允许使用不同的数据类型。要显示值属性正确地使用了内容presenter与每个数据类型我可能会使用一个DataTemplate。
I have an ItemsControl that binds to a list of items. These items have a name and value property. The value property is of type Object to allow different datatypes to be used. To display the value property correctly I use a ContentPresenter with a datatemplate for every datatype I might use.
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Name}"/>
<GridSplitter Width="1"
Grid.RowSpan="4" Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<ContentPresenter Grid.Column="2" Content="{Binding Value}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Int32}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Right"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Double}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Right"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
HorizontalAlignment="Center"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
内容presenter使用正确的数据类型和伟大工程。我的问题是,在编辑这些值不具有上结合的项目的任何影响。我怀疑这是因为我绑定到内容presenter的内容属性,而不是直接价值。我已经使用Content presenter这样的尝试:
The ContentPresenter uses the correct datatype and works great. My problem is that editing these values does not have any effect on the bound items. I suspect it is because I bind to the content property of the ContentPresenter rather than directly to the Value. I've tried using the ContentPresenter like this:
<ContentPresenter Grid.Column="2" Content="{Binding}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Value}"
BorderThickness="0"/>
</DataTemplate>
不过这样一来正确的DataTemplate没有选择,它只是显示的对象,而不是如String。我也试着离开了路径结合的DataTemplate中是这样的:
But this way the correct DataTemplate isn't selected and it just displays the Object instead of a String for example. I also tried to leave out the path in the binding of the DataTemplate like this:
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding}" BorderThickness="0"/>
</DataTemplate>
有了这个,我得到一个异常告诉我使用Path或XPath属性。
With this I get an exception telling me to use the Path or XPath attribute.
所以我的问题是:我怎么正确地绑定到该值,使其显示用正确的DataTemplate和值的任何编辑应用到绑定项。
So my question is: how do I correctly bind to the Value so it displays with the right DataTemplate and that any editing of the values is applied to the bound item.
顺便说一句出于某种原因,在我的问题缩进得多格式化code块的第一行之后。我试图修复它,但我不明白发生了什么。
Btw for some reason the formatted code blocks in my question indent much more after the first line. I tried fixing it but I don't understand what's happening.
已经在我的解决方案我也遇到了不能够列表数据类型添加到的DataTemplates问题不舒服。最后我用这导致好得多code一DataTemplateSelector。在这里,它是:
Already being uncomfortable with my solution I also ran into the problem of not being able to add a List DataType to the DataTemplates. I ended up using a DataTemplateSelector which resulted in much nicer code. Here it is:
在ContentControl中。
The ContentControl. A container for the data which the DataTemplate is applied over:
<ContentControl Grid.Column="2" Content="{Binding}"
ContentTemplateSelector="{StaticResource propertyItemTemplateSelector}">
</ContentControl>
几的DataTemplates和声明中DataTemplateSelector:
A few DataTemplates and a declaration for the DataTemplateSelector:
<Style.Resources>
<local:PropertyTemplateSelector x:Key="propertyItemTemplateSelector"/>
<DataTemplate x:Key="dtStringValue">
<TextBox Text="{Binding Path=Value}"
BorderThickness="0"
IsReadOnly="{Binding Path=IsReadOnly}">
</TextBox>
</DataTemplate>
<DataTemplate x:Key="dtIntegerValue">
<TextBox Text="{Binding Path=Value}"
TextAlignment="Right"
BorderThickness="0"
IsReadOnly="{Binding Path=IsReadOnly}"/>
</DataTemplate>
...
在code为DataTemplateSelector:
The code for the 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;
}
....