17

在 WPF 数据网格中,我有一个定义为 DataGridTemplateColumn 的列,我需要在各种列上使用它。作为一个非常简化的示例,请将以下内容视为虚拟示例:

<DataGrid ItemsSource="{Binding Path=ItemList, Mode=OneWay}" AutoGenerateColumns="False" >                
    <DataGrid.Columns>

        <DataGridTemplateColumn Header="Name" MinWidth="130" Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <DockPanel LastChildFill="True">
                        <Image Source="component/Images/test.png"/>
                        <TextBlock Text="{Binding Path=Name, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
                    </DockPanel>                                
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <DockPanel LastChildFill="True">
                        <Image Source="component/Images/test.png"/>
                        <TextBox Text="{Binding Path=Name, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
                    </DockPanel>
                </DataTemplate>                            
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>

        <DataGridTextColumn Header="Company" Binding="{Binding Company, ValidatesOnDataErrors=True}" MinWidth="115" Width="Auto"/>                    
    </DataGrid.Columns>
</DataGrid>

举个简单的例子,我如何将用于 Header=Name 的列的相同模板应用到 Header=Company 的列,而不必为每一列复制整个模板?

我已经找到了这个之前的 SO question的答案,他们在其中使用以下资源进行了解释:

<Application.Resources> 
     <DataTemplate x:Key="CellTemplate"> 
     ... 
     </DataTemplate> 
     <DataTemplate x:Key="CellEdintingTemplate"> 
     ... 
     </DataTemplate> 
</Application.Resources> 

<DataGrid Style="{StaticResource MainGridStyle}"> 
    <DataGrid.Columns> 
        <DataGridTemplateColumn CellTemplate="{StaticResource MyFirstColumnCellTemplate}" CellEdintingTemplate="{StaticResource MyFirstColumnCellEdintingTemplate}"/> 
        ... 
    </DataGrid.Columns> 
<DataGrid>  

这让我达到了 95%,但我缺少的最后一点是如何处理数据绑定?如何在模板中创建某种类型的占位符,然后在网格中进行实际绑定?

编辑 我一直在寻找并发现问题Create Common DataGridTemplateColumn这听起来像我想做的事情实际上目前可能是不可能的。因此,如果其他人曾经试图这样做,并且看到这个问题,我不能保证这是不可能的,但从这个链接看来它可能是。所以只需要复制每一列的所有模板代码。

4

2 回答 2

14

您可以将属性设置为CellStyle覆盖.TemplateDataGridCell

在 中Template,使用ContentPresenter绑定到TemplatedParent.Content要放置 DataGridCell 内容的任何位置的 a,TemplatedParent因为DataGridCell

例如,

<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>
于 2012-08-07T18:20:25.753 回答
5

链接Create Common DataGridTemplateColumn中有一个解决方案。

Poptart911 制作了一个DatagridBoundTemplateColumn,它可以用来替换DataGridTemplateColumn,允许你在列上设置“Binding”属性。因此,您可以重用 DataTemplate 并将不同的 DataContext 分配给不同列的模板。

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;
    }
}
}

例如,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 和数据类型

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; }
}
于 2018-03-28T10:00:32.573 回答