【问题标题】:How to reuse WPF DataGridTemplateColumn (including binding)如何重用 WPF DataGridTemplateColumn(包括绑定)
【发布时间】:2012-08-07 15:43:06
【问题描述】:

在 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 列,而不必为每一列复制整个模板?

我找到了this previous 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 听起来我想做的事情实际上目前可能是不可能的。因此,如果其他人试图这样做,并且看到这个问题,我不能保证这是不可能的,但从这个链接看来它可能是。所以只需要复制每一列的所有模板代码。

【问题讨论】:

    标签: wpf resources datagridtemplatecolumn


    【解决方案1】:

    您可以将CellStyle 属性设置为覆盖DataGridCellTemplate 的样式。

    Template 中,使用绑定到TemplatedParent.ContentContentPresenter 来放置DataGridCell 的内容,因为TemplatedParentDataGridCell

    例如,

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

    【讨论】:

    • ContentPresenter 是否可以使用附近某处资源中定义的 DataTemplate?
    【解决方案2】:

    链接Create Common DataGridTemplateColumn有解决办法。

    Popart911 制作了一个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; }
    }
    

    【讨论】:

    • 注意:要使用DataTemplate内的绑定,只需使用{Binding .}
    • @Terrence 或者更简单的{Binding}
    • 如何在 CellEditingTemplate 中使用双向绑定?
    • @MichelJansson 查看我添加的示例。
    • @YantingChen,非常感谢您的更新 - 它突出了我无法让它工作的原因。我没想到必须创建模型结构,其中我要绑定的每个属性都需要一个具有通用名称的子属性。为了解决这个要求,我在DataGridBoundTemplateColumn 中添加了一个绑定代理,它允许我像往常一样绑定到我的原始属性。如果有人对此感兴趣,我可以将其作为单独的答案发布。
    猜你喜欢
    • 2011-02-06
    • 2012-10-13
    • 1970-01-01
    • 2019-05-09
    • 2011-10-28
    • 2010-10-10
    • 2014-07-17
    • 2011-07-17
    • 2012-04-21
    相关资源
    最近更新 更多