wpf - 应用于不同模型的 Listbox DataTemplate
问题描述
我有两个表,其中也只包含一个作为键的值。我创建了一个列表框来显示和修改它。
- 表1是
TTypes1
,字段是Type1
String - 表2是
TTypes2
,字段是Type2
String
我写了这个DataTemplate
:
<DataTemplate x:Key="ListboxItems">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding}" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<!-- edit to swap with save -->
<Button
Content=""
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="Save"
Visibility="{Binding IsVisible}" />
<!-- Cancel - visible only on edit -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Delete -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Add -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
</StackPanel>
</Grid>
</DataTemplate>
这是列表框,但我无法让它按我的意愿工作。
如果我这样离开它:
<Label Grid.Column="0" Content="{Binding}" />
我没有看到文字,而是看到类型TTypes1
or TTypes2
。
但如果我写:
<Label Grid.Column="0" Content="{Binding Type1}" />
然后我不能在TType2
列表框中使用它。
这是我使用它的地方:
<ScrollViewer
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
Margin="2"
AlternationCount="2"
BorderThickness="1"
ItemsSource="{Binding TTypes1}"
SelectedIndex="0"
SelectionMode="Single"
ItemTemplate="{StaticResource ListboxItems}"
Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
</ListBox>
</ScrollViewer>
第二个是:
<ScrollViewer
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
Margin="2"
AlternationCount="2"
BorderThickness="1"
ItemsSource="{Binding TTypes2}"
SelectedIndex="0"
SelectionMode="Single"
ItemTemplate="{StaticResource ListboxItems}"
Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
</ListBox>
</ScrollViewer>
我错过了什么?
解决方案
多个数据模板
处理这种情况的常用方法是为每种类型创建一个不同的数据模板,例如 forTType1
和TType2
。
<DataTemplate x:Key="ListboxItemsTType1"
DataType="{x:Type local:TType1}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="{Binding Type1}" />
<!-- ...other markup. -->
</Grid>
</DataTemplate>
<DataTemplate x:Key="ListboxItemsTType2"
DataType="{x:Type local:TType2}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="{Binding Type2}" />
<!-- ...other markup. -->
</Grid>
</DataTemplate>
ListBox
在你的es中引用具体的模板。您还可以x:Key
从数据模板中删除 ,因此它们会自动应用于ListBox
. 这也适用于列表中的混合项目。
<ScrollViewer Grid.Row="0"
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
ItemTemplate="{StaticResource ListboxItems}"
...
</ListBox>
</ScrollViewer>
<ScrollViewer Grid.Row="1"
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
...
ItemTemplate="{StaticResource ListboxItems}"
</ListBox>
</ScrollViewer>
其他方法
如果您真的想保留单个数据模板,则必须根据绑定为数据上下文的对象的项目类型来切换绑定。有多种方法可以实现这一目标。
这是一个使用转换器的示例,该转换器将对象从相关问题转换为其类型,复制它。样式将使用数据触发器来应用基于该类型的正确绑定。Label
<local:DataTypeConverter x:Key="DataTypeConverter" />
<DataTemplate x:Key="ListboxItems">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0">
<Label.Style>
<Style TargetType="{x:Type Label}"
BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="Content"
Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
Value="{x:Type local:TType1}">
<Setter Property="Content"
Value="{Binding Type1}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
Value="{x:Type local:TType2}">
<Setter Property="Content"
Value="{Binding Type2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<StackPanel Grid.Column="1"
Orientation="Horizontal">
<!-- edit to swap with save -->
<Button Content=""
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="Save"
Visibility="{Binding IsVisible}" />
<!-- Cancel - visible only on edit -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Delete -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Add -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
</StackPanel>
</Grid>
</DataTemplate>
其他完全依赖代码但更易于重用的选项是:
- 创建一个与触发器执行相同操作的特殊值转换器,返回在代码中创建的绑定,该绑定具有基于类型的属性路径
- 创建一个自定义标记扩展,根据类型自动选择属性路径
我没有提供这些选项的示例,因为它们很复杂并且很大程度上取决于您的要求。此外,我推荐第一种方法来创建多个数据模板,因为我认为从维护和灵活性的角度来看这是最有利的。
推荐阅读
- python - 模糊正则表达式:替换的模糊计数始终为 1
- javascript - 如何在 React 中使用 map 函数显示对象数组中的图像链接?
- flutter - RenderFlex 子级具有非零弹性,但传入的高度约束是无界的
- python - 根据一行中的关键字将csv分成几部分,然后转置
- python - pyspark concat_ws 用于数组到字符串
- php - 如何让活动的 PHP 文件在 Microsoft Visual Code 中运行?
- docker - 如何在 ubuntu 容器中使用 docker
- bash - 使用 PKI 对 bash 应用程序实施限制
- python - 使用 Seaborn 绘制条形图
- powerbi - Power BI 查询按顺序运行