Multiple DataGrid columns with the same custom template/style but different binding/context

梦想的初衷 提交于 2020-08-24 03:27:05

问题


I would like to create a custom DataGrid column (or a DataGridCell style), ideally in XAML, and use it multiple times without any code duplication. It should contain multiple different controls, each accessing a different property of the data object.

There seem to be two ways of doing this:

  • DataGridTemplateColumn with a custom CellTemplate (see an example here)
  • custom DataGridCell style (something like this or this)

Both of these solutions suffer from the same issue. When specifying the bindings for the internal controls, they always seem to be related to the whole DataGrid row rather than the cell.

DataGridTemplateColumn does not have a Binding attribute, so its CellTemplate is bound to the whole row, making it impossible to reuse the same template for multiple columns, each accessing a different property of the row object.

Similarly, I can access the content of DataGridTextColumn in a style that overrides the Template via {TemplateBinding Content} (see here), but I cannot find a way to access the content's properties, so I assume that is not possible.

Here is a dummy example of such DataGrid to illustrate my situation:

public class Name
{
    public string First { get; set; }
    public string Last { get; set; }

    public override string ToString() => $"{First} {Last}";
}

public class Team
{
    public Name First { get; set; }
    public Name Second { get; set; }
    public Name Third { get; set; }
}

public ObservableCollection<Team> DataList { get; } = new ObservableCollection<Team>();
<DataGrid ItemsSource="{Binding DataList}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="First" Binding="{Binding First}"/>
        <DataGridTextColumn Header="Second" Binding="{Binding Second}"/>
        <DataGridTextColumn Header="Third" Binding="{Binding Third}"/>
    </DataGrid.Columns>
</DataGrid>

Now, I would like to separate the First and Last properties of Name and render them using individual controls, both still inside of the same DataGrid cell. The motivation here could be to have First in black and Last in red, for example, or anything else that requires them to be in two separate controls.

Example of a DateTemplate (applied as CellTemplate on DataGridTemplateColumn):

<DataTemplate x:Key="NameTemplate">
    <StackPanel>
        <Label Content="{Binding First}"/>
        <Label Content="{Binding Last}"/>
    </StackPanel>
</DataTemplate>

Example of a DataGridCell style (applied as CellStyle on a DataGridTextColumn):

<Style x:Key="NameStyle" TargetType="{x:Type DataGridCell}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <DockPanel>
                    <ContentPresenter Content="{Binding First}"/>
                    <ContentPresenter Content="{Binding Last}"/>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Is there any way to make a code similar to either of the examples above work?

Of course, it is possible to copy-paste the same exact template/style for each column, each accessing the relevant row-level property of Name, but this is an awful solution that would be a nightmare to maintain and it just does not scale.

I have seen a handful of similar questions, but not a single one of them had a XAML solution that was not extremely complex. This just seems like something that should be pretty easy to do, but I am unable to find a straightforward solution anywhere. The most similar question I found was probably this, but it was never really answered in a way that would help my case.

Two possible solutions were to either build and apply the XAML code (template/style) at runtime or to add an attached property to the column, which would allow me to pass the properties separately. Both of those seem like terrible hacks to me and I would much prefer avoiding them. Another solution is to create a new control (as suggested here) derived from DataGridBoundColumn (such as this), but I had no luck with that either and it a fairly complicated solution compared to defining a DataTemplate.

PS: While finishing up the question and looking for the links to other questions and answers, I have stumbled upon the DataGridBoundTemplateColumn implementation, which pretty much works, but I would still prefer a more XAML-native solution using just a template/style rather than creating a new control that still requires the template on top of itself.

来源:https://stackoverflow.com/questions/63443678/multiple-datagrid-columns-with-the-same-custom-template-style-but-different-bind

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!