如何编写具有某些功能的 DataTemplate 作为资源
How to write a DataTemplate with some functionality as a resource
我的应用程序中有一些列表框,其中包含电话簿的联系人。我希望所有这些 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 中显示。因此,一种方法是复制此模板及其在每个 Window/Page 中具有联系人列表框的处理程序,如下所示:
<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 吗?
请尝试下一个解决方案:
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 代码:
<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>
如果您在使用代码时遇到问题,我很乐意提供帮助。
此致。
您可以在您的词典中包含事件处理程序,只要它们是词典的一部分——即,词典背后有一些代码。这类似于 Page
s 和 UserControl
s;您需要添加一个 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);
}
}
在我的 window 中,是这样的:
<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 可能有用。
我的应用程序中有一些列表框,其中包含电话簿的联系人。我希望所有这些 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 中显示。因此,一种方法是复制此模板及其在每个 Window/Page 中具有联系人列表框的处理程序,如下所示:
<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 吗?
请尝试下一个解决方案:
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 代码:
<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>
如果您在使用代码时遇到问题,我很乐意提供帮助。
此致。
您可以在您的词典中包含事件处理程序,只要它们是词典的一部分——即,词典背后有一些代码。这类似于 Page
s 和 UserControl
s;您需要添加一个 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);
}
}
在我的 window 中,是这样的:
<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 可能有用。