How to reuse WPF DataGridTemplateColumn (including binding) How to reuse WPF DataGridTemplateColumn (including binding) wpf wpf

How to reuse WPF DataGridTemplateColumn (including binding)


You can set the CellStyle property to a style that overwrites the Template for the DataGridCell.

In the Template, use a ContentPresenter that is bound to the TemplatedParent.Content wherever you want to place the DataGridCell's Content, since the TemplatedParent is the DataGridCell

For example,

<Style x:Key="MyCellStyle" TargetType="{x:Type DataGridCell}">    <Setter Property="Template">        <Setter.Value>            <ControlTemplate>                <DockPanel LastChildFill="True">                    <Image Source="component/Images/test.png"/>                    <ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" />                </DockPanel>              </ControlTemplate>        </Setter.Value>    </Setter></Style><DataGrid ItemsSource="{Binding ItemList}" AutoGenerateColumns="False">    <DataGrid.Columns>        <DataGridTextColumn Header="Name" Binding="{Binding Name}" CellStyle="{StaticResource MyCellStyle}" MinWidth="130" Width="Auto" />        <DataGridTextColumn Header="Company" Binding="{Binding Company}" CellStyle="{StaticResource MyCellStyle}" MinWidth="115" Width="Auto"/>                        </DataGrid.Columns></DataGrid>


There is a solution in the link Create Common DataGridTemplateColumn.

Poptart911 made a DatagridBoundTemplateColumn which can be used for replacing DataGridTemplateColumn, allowing you to set the "Binding" property on the column. Hence you can reuse the DataTemplate and assign different DataContext to the template for different column.

using System.Windows;using System.Windows.Controls;using System.Windows.Data;namespace OwensWpfFunStuff{public class DataGridBoundTemplateColumn : DataGridBoundColumn{    public DataTemplate CellTemplate { get; set; }    public DataTemplate CellEditingTemplate { get; set; }    protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell, object dataItem)    {        return Generate(dataItem, CellTemplate);    }    protected override System.Windows.FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)    {        return Generate(dataItem, CellEditingTemplate);    }    private FrameworkElement Generate(object dataItem, DataTemplate template)    {        var contentControl = new ContentControl { ContentTemplate = template, Content = dataItem };        BindingOperations.SetBinding(contentControl, ContentControl.ContentProperty, Binding);        return contentControl;    }}}

For example, XAML:

<DataGrid ItemsSource="{Binding Devices}" AutoGenerateColumns="False">    <DataGrid.Resources>        <DataTemplate x:Key="VariableTemplate">            <TextBlock Text="{Binding VarName}"/>        </DataTemplate>        <DataTemplate x:Key="VariableEditingTemplate">            <TextBox Text="{Binding VarName, UpdateSourceTrigger=PropertyChanged}"/>        </DataTemplate>    </DataGrid.Resources>    <DataGrid.Columns>        <local:DataGridBoundTemplateColumn Header="Input Variable"                                            Binding="{Binding InputVariable}"                                            CellTemplate="{StaticResource VariableTemplate}"                                            CellEditingTemplate="{StaticResource VariableEditingTemplate}">        </local:DataGridBoundTemplateColumn>        <local:DataGridBoundTemplateColumn Header="Output Variable"                                            Binding="{Binding OutputVariable}"                                            CellTemplate="{StaticResource VariableTemplate}"                                            CellEditingTemplate="{StaticResource VariableEditingTemplate}">        </local:DataGridBoundTemplateColumn>    </DataGrid.Columns></DataGrid>

ViewModel and data types

class MainWindowVM{    public List<Device> Devices { get; set; } = new List<Device>()    {        new Device()        {            InputVariable = new MyVariable()            {                VarName = "theInputVar"            },            OutputVariable = new MyVariable()            {                VarName = "theOutputVar"            }        }    };}public class Device{    public MyVariable InputVariable { get; set; }    public MyVariable OutputVariable { get; set; }}public class MyVariable{    public string VarName { get; set; }}