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>
If your
DataTemplate
s are exactly the same then just put one into aResources
section and then simply reference it:UPDATE >>>
Ok, so if you have different
Binding
s inside theDataTemplate
, then you'll have to use aUserControl
instead. You will then be able to declareDependencyProperty
s for the variable properties and bind to them from theDataGridColumn
:If you define a
DependencyProperty
for each differentBinding
, then you'll be able to set them like this: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.