簡體   English   中英

為ItemsControl創建可重用的DataTemplate資源

[英]Creating a re-usable DataTemplate resource for an ItemsControl

我目前有什么

我目前有一個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”和“ 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>

希望這可以幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM