【问题标题】:How to write a DataTemplate with some functionality as a resource如何编写具有某些功能的 DataTemplate 作为资源
【发布时间】:2016-01-26 11:22:35
【问题描述】:

我的应用程序中有一些列表框,其中包含电话簿的联系人。我希望所有这些 ListBox 都有一个 DataTemplate 作为它们的 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 中的样式并添加到控件中,因为事件处理程序不能出现在 ResourceDictionaries 中。因此,一种方法是复制此模板及其在每个窗口/页面中的处理程序,这些处理程序具有如下联系人列表框:

<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>

有没有其他方法可以让我编写一个具有某些功能的 DataTemplate 并在我想要的任何地方使用它?我应该写一个 UserControl 而不是 DataTemplate 吗?

【问题讨论】:

  • 用命令绑定替换点击处理程序。将 MenuItem 的 Command 属性绑定到视图模型中的 ICommand 属性。

标签: c# wpf datatemplate wpf-style


【解决方案1】:

请尝试下一个解决方案:

Xaml 代码:

<Window x:Class="DataTemplateInResDectReuseHelpAttempt.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dataTemplateInResDectReuseHelpAttempt="clr-namespace:DataTemplateInResDectReuseHelpAttempt"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <dataTemplateInResDectReuseHelpAttempt:MainDataContext/>
</Window.DataContext>
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="ContactsDataTemplateResourceDictionary.xaml"></ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding BaseModels}">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <ContentControl Content="{Binding }" ContentTemplate="{StaticResource ContactItemTemplate}"></ContentControl>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
</Grid></Window>

ViewModel 和模型

    class MainDataContext
{
    private ICommand _viewCommand;
    private ICommand _deleteCommand;
    private ICommand _editCommand;

    public MainDataContext()
    {
        BaseModels = new ObservableCollection<BaseModel>
        {
            new BaseModel(EditCommand, DeleteCommand, ViewCommand){LastName = "Omar", FirstName = "Khayyam"},
            new BaseModel(EditCommand, DeleteCommand, ViewCommand){LastName = "Chekhov", FirstName = "Anton"},
            new BaseModel(EditCommand, DeleteCommand, ViewCommand){LastName = "Lau", FirstName = "Meir"},
        };
    }

    public ICommand ViewCommand
    {
        get { return _viewCommand ?? (_viewCommand = new RelayCommand<object>(View)); }
    }

    private void View(object obj)
    {

    }

    public ICommand DeleteCommand
    {
        get { return _deleteCommand ?? (_deleteCommand = new RelayCommand<object>(Delete)); }
    }

    private void Delete(object obj)
    {

    }

    public ICommand EditCommand
    {
        get { return _editCommand ?? (_editCommand = new RelayCommand<object>(Edit)); }
    }

    private void Edit(object obj)
    {

    }

    public ObservableCollection<BaseModel> BaseModels { get; set; } 
}

public class BaseModel:BaseObservableObject
{
    private string _firstName;
    private string _lastName;
    private readonly ICommand _editCommand;
    private readonly ICommand _deleteCommand;
    private readonly ICommand _viewCommand;

    public BaseModel(ICommand editCommand, ICommand deleteCommand, ICommand viewCommand)
    {
        _editCommand = editCommand;
        _deleteCommand = deleteCommand;
        _viewCommand = viewCommand;
    }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            OnPropertyChanged();
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value;
            OnPropertyChanged();
        }
    }

    public ICommand EditCommand
    {
        get { return _editCommand; }
    }

    public ICommand DeleteCommand
    {
        get { return _deleteCommand; }
    }

    public ICommand ViewCommand
    {
        get { return _viewCommand; }
    }
}

资源字典代码:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="DataTemplateBackgroundBrush" Color="Azure"/>
<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" Command="{Binding EditCommand}" CommandParameter="{Binding }"/>
                <MenuItem Header="Delete" Command="{Binding DeleteCommand}" CommandParameter="{Binding }"/>
                <MenuItem Header="View" Command="{Binding ViewCommand}" CommandParameter="{Binding }"/>
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</DataTemplate></ResourceDictionary>

如果您遇到代码问题,我很乐意提供帮助。

问候。

【讨论】:

    【解决方案2】:

    可以在您的字典中拥有事件处理程序,只要它们是字典的一部分——即字典背后有一些代码。这类似于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.


    更新:关于 ContextMenus 和模板

    一小部分附加信息:this article 上的 cmets 对 ContextMenu 模板进行了一些讨论,可能很有启发性。

    ...和one more TextBox ContextMenu link 可能有用。

    【讨论】:

      猜你喜欢
      • 2013-04-23
      • 1970-01-01
      • 2016-04-23
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多