如何将正确的上下文传递给 WPF ListView 的 ItemTemplate 中的 DataTemplate
How to pass the right Context to a DataTemplate within an ItemTemplate of a WPF ListView
在我的 WPF 应用程序中有一个 ListView
定义如下:
<ListView
HorizontalContentAlignment="Stretch"
DockPanel.Dock="Top"
Grid.IsSharedSizeScope="True"
ItemsSource="{Binding Path=ListSource}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ParameterIconSize" />
<ColumnDefinition
Width="Auto"
MaxWidth="100"
SharedSizeGroup="ParameterDescriptionSize" />
<ColumnDefinition
Width="Auto"
MinWidth="40"
SharedSizeGroup="ParameterValueSize" />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
MaxHeight="50"
Source="{Binding Path=Icon}" />
<ContentPresenter
Grid.Column="2"
Content="{Binding Path=RenderValue, Converter={StaticResource RenderObjToValueConverter}}"
ContentTemplateSelector="{StaticResource ResourceKey=RenderTemplateSelector}"
/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我已将 Resources
中的所有内容定义如下:
<!-- TEXT -->
<DataTemplate x:Key="TextValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<TextBlock
MaxWidth="75"
Margin="5,0"
VerticalAlignment="Center"
Background="Red"
DockPanel.Dock="Top"
FontSize="14"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextTrimming="CharacterEllipsis">
<TextBlock.ToolTip>
<TextBlock
MaxWidth="100"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
</DockPanel>
</DataTemplate>
<!-- IMAGE -->
<DataTemplate x:Key="ImageValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<Image MaxHeight="50" Source="{Binding Path=CurrentValueImage}" />
</DockPanel>
</DataTemplate>
<!-- COMBO BOX -->
<DataTemplate x:Key="ComboValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<TextBlock
Grid.Column="1"
MaxWidth="75"
Margin="5,0"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextTrimming="CharacterEllipsis">
<TextBlock.ToolTip>
<TextBlock
MaxWidth="100"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
<ComboBox/>
</DockPanel>
</DataTemplate>
<sel:ParameterVisualizationTemplateSelector
x:Key="RenderTemplateSelector"
ComboTemplate="{StaticResource ResourceKey=ComboValueTemplate}"
GraphicTemplate="{StaticResource ResourceKey=ImageValueTemplate}"
TextTemplate="{StaticResource ResourceKey=TextValueTemplate}" />
一切都编译并运行,但我无法正确地将 ListViewItem
传递给内部数据模板。
我想做的是能够根据图像、文本和组合框之间的某种逻辑(此处未显示)更改显示的内容。这些控件内部的内容在 ListViewItem
中定义。如您所见,我尝试编写一个 return 相应类型(图像、文本、数据列表)的转换器,但我缺少各种 DataTemplates
之间的 link。
最终编辑:根据@mm8 的回答,我发现真正的问题不是传递上下文,而是传递的 属性 没有被正确处理,然后不会设置任何值没有给出任何绑定错误。
当您在模板中设置 DataContext="{StaticResource VM}"
时,实际上是在“覆盖”默认值 DataContext
,它是 [=15= 的 ListSource
源集合中的当前项目].
So, if I understand correctly, the "dependency" chain is something like control <- textItemtemplate <- ListViewItemTemplate <- Viewmodel, so the final control automatically "inherits" the object?
您将 ListView
的 ItemsSource
绑定到名为 ListSource
:
的源集合 属性
<ListView ... ItemsSource="{Binding Path=ListSource}">
ListView
的 ItemTemplate
中的根元素(在本例中为 Grid
)的默认 DataContext
将是 [=14 中的元素=].
这意味着如果 ListSource
returns 一个 IEnumerable<T>
你可以直接绑定到 T
类型的任何 public 属性 ItemTemplate
前提是您没有在模板中的某处明确设置 DataContext
属性。
因此,在您的示例中,Icon
应该是 T
的 属性(无论您的类型 T
是什么):
<Image Grid.Column="0"
MaxHeight="50"
Source="{Binding Path=Icon}" />
例如,如果您从 TextValueTemplate
中删除 DataContext="{StaticResource VM}"
,只要在 Description
属性 中定义了一个 Description
属性从 RenderValue
属性.
的转换器返回的对象
在我的 WPF 应用程序中有一个 ListView
定义如下:
<ListView
HorizontalContentAlignment="Stretch"
DockPanel.Dock="Top"
Grid.IsSharedSizeScope="True"
ItemsSource="{Binding Path=ListSource}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ParameterIconSize" />
<ColumnDefinition
Width="Auto"
MaxWidth="100"
SharedSizeGroup="ParameterDescriptionSize" />
<ColumnDefinition
Width="Auto"
MinWidth="40"
SharedSizeGroup="ParameterValueSize" />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
MaxHeight="50"
Source="{Binding Path=Icon}" />
<ContentPresenter
Grid.Column="2"
Content="{Binding Path=RenderValue, Converter={StaticResource RenderObjToValueConverter}}"
ContentTemplateSelector="{StaticResource ResourceKey=RenderTemplateSelector}"
/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我已将 Resources
中的所有内容定义如下:
<!-- TEXT -->
<DataTemplate x:Key="TextValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<TextBlock
MaxWidth="75"
Margin="5,0"
VerticalAlignment="Center"
Background="Red"
DockPanel.Dock="Top"
FontSize="14"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextTrimming="CharacterEllipsis">
<TextBlock.ToolTip>
<TextBlock
MaxWidth="100"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
</DockPanel>
</DataTemplate>
<!-- IMAGE -->
<DataTemplate x:Key="ImageValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<Image MaxHeight="50" Source="{Binding Path=CurrentValueImage}" />
</DockPanel>
</DataTemplate>
<!-- COMBO BOX -->
<DataTemplate x:Key="ComboValueTemplate">
<DockPanel DataContext="{StaticResource VM}">
<TextBlock
Grid.Column="1"
MaxWidth="75"
Margin="5,0"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextTrimming="CharacterEllipsis">
<TextBlock.ToolTip>
<TextBlock
MaxWidth="100"
Text="{Binding Path=Description, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
<ComboBox/>
</DockPanel>
</DataTemplate>
<sel:ParameterVisualizationTemplateSelector
x:Key="RenderTemplateSelector"
ComboTemplate="{StaticResource ResourceKey=ComboValueTemplate}"
GraphicTemplate="{StaticResource ResourceKey=ImageValueTemplate}"
TextTemplate="{StaticResource ResourceKey=TextValueTemplate}" />
一切都编译并运行,但我无法正确地将 ListViewItem
传递给内部数据模板。
我想做的是能够根据图像、文本和组合框之间的某种逻辑(此处未显示)更改显示的内容。这些控件内部的内容在 ListViewItem
中定义。如您所见,我尝试编写一个 return 相应类型(图像、文本、数据列表)的转换器,但我缺少各种 DataTemplates
之间的 link。
最终编辑:根据@mm8 的回答,我发现真正的问题不是传递上下文,而是传递的 属性 没有被正确处理,然后不会设置任何值没有给出任何绑定错误。
当您在模板中设置 DataContext="{StaticResource VM}"
时,实际上是在“覆盖”默认值 DataContext
,它是 [=15= 的 ListSource
源集合中的当前项目].
So, if I understand correctly, the "dependency" chain is something like control <- textItemtemplate <- ListViewItemTemplate <- Viewmodel, so the final control automatically "inherits" the object?
您将 ListView
的 ItemsSource
绑定到名为 ListSource
:
<ListView ... ItemsSource="{Binding Path=ListSource}">
ListView
的 ItemTemplate
中的根元素(在本例中为 Grid
)的默认 DataContext
将是 [=14 中的元素=].
这意味着如果 ListSource
returns 一个 IEnumerable<T>
你可以直接绑定到 T
类型的任何 public 属性 ItemTemplate
前提是您没有在模板中的某处明确设置 DataContext
属性。
因此,在您的示例中,Icon
应该是 T
的 属性(无论您的类型 T
是什么):
<Image Grid.Column="0"
MaxHeight="50"
Source="{Binding Path=Icon}" />
例如,如果您从 TextValueTemplate
中删除 DataContext="{StaticResource VM}"
,只要在 Description
属性 中定义了一个 Description
属性从 RenderValue
属性.