我的应用程序中有一些列表框,其中包含电话簿的联系人。我希望所有这些列表框都有一个数据模板作为它们的itemstemplates,其中包含一些功能,如编辑、删除和查看,如下代码所示:

<DataTemplate x:Key="ContactItemTemplate">
    <TextBlock Foreground="Black" Background="{StaticResource DataTemplateBackgroundBrush}" Padding="5,10" Margin="4,3">
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{0} {1}">
                <Binding Path="FirstName"/>
                <Binding Path="LastName"/>
            </MultiBinding>
        </TextBlock.Text>
        <TextBlock.ContextMenu>
            <ContextMenu FontFamily="B Yekan">
                <MenuItem Header="Edit" Click="btn_EditContact_Click"/>
                <MenuItem Header="Delete" Click="btn_DeleteContact_Click"/>
                <MenuItem Header="View" Click="btn_EditContact_Click"/>
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</DataTemplate>

它不能作为样式写入ResourceDictionary并添加到控件中,因为EventHandler不能在ResourceDictionary中显示。因此,一种方法是复制此模板以及每个窗口/页面中具有如下联系人列表框的处理程序:
<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/Styles/Controls_Style.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <DataTemplate x:Key="AttachmentsTemplate">
            <Border Height="150" Width="120" BorderThickness="1" BorderBrush="{StaticResource DefaultBorderBrush}" Margin="2">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Bottom" TextWrapping="WrapWithOverflow"/>
                    <Image Grid.Row="1" Source="{Binding Image}" Margin="5,0"/>
                </Grid>
            </Border>
        </DataTemplate>
    </ResourceDictionary>
</Page.Resources>

有没有其他方法可以让我只编写一次具有某些功能的数据模板,然后在任何需要的地方使用它?我应该写一个用户控件而不是一个数据模板吗?

最佳答案

只要事件处理程序是字典的一部分,就可以在字典中包含它们——也就是说,字典后面有一些代码。这类似于Pages和UserControls;您需要添加一个x:Class属性。例如,styles.xml可能如下所示:

<ResourceDictionary
    x:Class="WPF.Styles"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1">
    <DataTemplate x:Key="ContactItemTemplate" DataType="local:Person">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBlock
                Grid.Column="0"
                Foreground="Black"
                Background="Yellow"
                Padding="5,10"
                Margin="4,3"
                Text="{Binding Name}"
                >
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Edit!" Click="btn_EditContact_Click"/>
                        <MenuItem Header="Delete!" Click="btn_DeleteContact_Click"/>
                        <MenuItem Header="View!" Click="btn_EditContact_Click"/>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
            <Button
                Grid.Column="1"
                Content="Edit"
                Click="btn_EditContact_Click"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

…带有相应的styles.cs(请注意partial):
public sealed partial class Styles
{
    private void btn_EditContact_Click(object sender, EventArgs args)
    {
        Debug.WriteLine(args);
    }

    private void btn_DeleteContact_Click(object sender, EventArgs args)
    {
        Debug.WriteLine(args);
    }
}

在我的窗户里,像这样的东西:
<Grid.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Grid.Resources>

...

<ItemsControl
    ItemsSource="{Binding People}"
    Grid.Row="3"
    ItemTemplate="{StaticResource ContactItemTemplate}" />

为了完整性,模型对象:
public class Person
{
    public string Name { get; }

    public Person(string name)
    {
        Name = name;
    }
}

…和ItemsSource
public Person[] People { get; } =
    {
        new Person("Donald Duck"),
        new Person("Mickey Mouse"),
        new Person("Darth Vader"),
    };

一般来说,这很好——例如,单击按钮,调用btn_EdxtContact_Click。不幸的是,你的场景中包含TextBox的上下文菜单有一个问题;
details and possible workarounds in this post
更新:在上下文菜单和模板上
一小部分附加信息:this article上的评论有一些关于ContextMenu模板的讨论,可能会有启发性。
…而且one more TextBox ContextMenu link可能会被证明是有用的。

关于c# - 如何编写具有某些功能的DataTemplate作为资源,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35012679/

10-12 22:35