正在为ItemsControl创建可重复使用的DataTemplate资源
本文关键字:DataTemplate 资源 ItemsControl 创建 | 更新日期: 2023-09-27 17:59:50
我目前拥有的
我当前有一个ItemsControl,用于显示控件列表。由于每个"项"都包含多个控件,我通过指定DataTemplate来设置它。类似这样的东西(我删除了一些元素属性,使代码更容易遵循):
<ItemsControl x:Name="Items" ItemsSource="{Binding Path=MyItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0"/>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<c:MyControl />
<c:MyButton />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我想做什么
上面给出了我想要的功能,但我在一些地方有它,我想尽量减少重复的代码。关于上面的xaml,当重用DataTemplate时,唯一需要不同的是"MyButton"answers"MyControl"的控件。考虑到这一点,我定义上面XAML的理想方式是这样的:
<ItemsControl x:Name="Items" ItemsSource="{Binding Path=MyItems}">
<c:MyControl />
<c:MyButton />
</ItemsControl>
当然,我很高兴有一些变化,但希望我正在努力消除重复。
我尝试过的
到目前为止,我已经尝试在我的资源文件中创建一个模板,但效果不太好,我甚至不确定我是否走上了正确的道路。这就是我所拥有的:
<DataTemplate x:Key="MyTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" Fill="..." Data="..." />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<ItemsPresenter />
</StackPanel>
</Grid>
</DataTemplate>
我试着把它像这样应用到我的XAML:
<ItemsControl x:Name="Items" ItemsSource="{Binding Path=MyItems}" ItemTemplate="{StaticResource MyTemplate}">
<c:MyControl />
<c:MyButton />
</ItemsControl>
这一切都构建得很好,但在运行时我遇到了一个错误:"Items collection must be empty before using ItemsSource."
,这显然是我错误方法的副作用。
我做错了什么?我如何设置我的模板以使其按我希望的方式工作?
您可以创建一个派生的ItemsControl类,该类使用ContentControl
(而不是ContentPresenter
)作为项目容器类型:
public class MyItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new ContentControl();
}
}
现在,您可以将当前的DataTemplate分为一个"外部"可重用部分和一个"内部"部分,前者驻留在ContentControl的Template
中,后者由剩余的DataTemplate:定义
<!-- somewhere in Resources -->
<Style x:Key="ReusableItemContainerStyle" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" ... />
<ContentPresenter Grid.Column="1"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<local:MyItemsControl
ItemsSource="{Binding MyItems}"
ItemContainerStyle="{StaticResource ReusableItemContainerStyle}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<c:MyControl />
<c:MyButton />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</local:MyItemsControl>
更新:您还可以为Generic.xaml中的派生ItemsControl设置默认样式的可重用ItemContainerStyle,如下所示:
<Style TargetType="local:MyItemsControl"
BasedOn="{StaticResource {x:Type ItemsControl}}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" ... />
<ContentPresenter Grid.Column="1"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
然后,您还必须为ItemsControl:设置默认样式键
public class MyItemsControl : ItemsControl
{
static MyItemsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyItemsControl),
new FrameworkPropertyMetadata(typeof(MyItemsControl)));
}
protected override DependencyObject GetContainerForItemOverride()
{
return new ContentControl();
}
}
将模板作为新控件声明为:
<UserControl x:Class="UI.Views.NewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Name="myNewControl">
<Grid>
<ItemsControl x:Name="Items" ItemsSource="{Binding Path=MyItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0"/>
<ContentControl Grid.Row="1" Content="{Binding MyCustomControl, ElementName=myNewControl}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
MyCustomControl应该是控件的依赖项属性。
如何使用:
<MyNewControl>
<MyNewControl.MyCustomControl>
<StackPanel>
<MyControl/>
<MyButton/>
</StackPanel>
</MyNewControl.MyCustomControl>
</MyNewControl>
希望这能帮助