问题
I'm using a UserControl where the main control inside is a datagrid. All is working. However, some lines of my code are redundant since I implement the same trigger in each of the 48 columns.
How do I make a template for the datagridtemplatecolumn of the following code snippet? The only thing different in each column is the bound property. All the triggers and formatting are the same.
I would appreciate your help!
<DataGridTemplateColumn Header="5" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Background="{Binding _5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"
Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonUp">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.LastCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.MouseDragCom}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Background="{Binding _5_5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"
Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonUp">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.LastCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.MouseDragCom}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="6" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Background="{Binding _6, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"
Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonUp">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.LastCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.MouseDragCom}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
EDIT
So I followed Sheridan's suggestion with some revisions to make it shorter and simpler. Although our project leader suggested this method before, I had no idea on how to implement it prior to Sheridan's input. Kudos to him
This is the code for the UserControl we used. What it contains is exactly the same triggers we used from our original code above:
<UserControl x:Class="Widget5.View.DGInfo"
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"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:converter="clr-namespace:Widget5.Converter"
xmlns:dg="clr-namespace:Widget5.View"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="20">
<UserControl.Resources>
<converter:DataGridInfoToParamConverter x:Key="dgInfoConverter" />
</UserControl.Resources>
<TextBlock Background="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type dg:DGInfo}}}" Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}" >
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.LastCellCommand}" >
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.MouseDragCom}" >
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</UserControl>
And on the DataGridTemplateColumn itself, we just added the UserControl(DGInfo) and set its background like we did before. Saved thousands of lines because of this.
<DataGrid ...>
...
<DataGridTemplateColumn Header="6" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<View:DGInfo Background="{Binding _6, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
</DataGrid>
回答1:
If your DataTemplate
s are exactly the same then just put one into a Resources
section and then simply reference it:
<DataGrid.Resources>
<DataTemplate x:Key="TheDataTemplate">
<TextBlock
Background="{Binding _5_5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"
Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonUp">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.LastCellCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.MouseDragCom}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
<Binding Path="DataContext"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridCell}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</DataGrid.Resources>
...
<DataGridTemplateColumn CellTemplate="{StaticResource TheDataTemplate}"
Header="" MaxWidth="10" />
...
UPDATE >>>
Ok, so if you have different Binding
s inside the DataTemplate
, then you'll have to use a UserControl
instead. You will then be able to declare DependencyProperty
s for the variable properties and bind to them from the DataGridColumn
:
<UserControl ... >
<TextBlock
Background="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type yourXmlNamespacePrefix:YourUserControl}}}"
Margin="-1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding StartCellCommand, RelativeSource={RelativeSource AncestorType={x:Type yourXmlNamespacePrefix:YourUserControl}}}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource dgInfoConverter}">
<Binding Path="Column"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type yourXmlNamespacePrefix:YourUserControl}}" />
<Binding Path="SomeProperty"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type yourXmlNamespacePrefix:YourUserControl}}" />
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
...
</i:Interaction.Triggers>
</TextBlock>
</UserControl>
If you define a DependencyProperty
for each different Binding
, then you'll be able to set them like this:
...
<DataGridTemplateColumn Header="" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<yourXmlNamespacePrefix:YourUserControl Background="{Binding _5_5,
Converter={StaticResource ResourceKey=hourSlotColorConverter},
UpdateSourceTrigger=PropertyChanged}" StartCellCommand="{Binding RelativeSource=
{RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.StartCellCommand}"
Column="{Binding Column, RelativeSource={RelativeSource AncestorType={x:Type
DataGridCell}}}" SomeProperty="{Binding DataContext, RelativeSource={RelativeSource
AncestorType={x:Type DataGridCell}}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn >
...
It's still a lot of code, but it's much less than before. I didn't finish this example for all of your properties, but I'm guessing that you'll get the idea.
来源:https://stackoverflow.com/questions/20368667/datagridtemplatecolumn-invokecommandaction-template