我目前拥有什么
我目前有一个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时唯一需要改变的是&#34; MyButton&#34;和&#34; MyControl&#34;。考虑到这一点,我在上面定义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."
这显然是我不正确的方法的副作用。
我做错了什么?如何设置我的模板以我想要的方式工作?
答案 0 :(得分:2)
您可以为项容器类型创建一个使用ContentControl
(而不是ContentPresenter
)的派生ItemsControl类:
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();
}
}
答案 1 :(得分:1)
将模板声明为新控件:
<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>
希望这有帮助