将CellTemplate分配给C#/ WPF中的动态生成的DataGridTemplateColumn

时间:2016-03-14 20:38:05

标签: c# wpf

我目前有一个DataGridDataTable通过ItemSource绑定。我希望能够将CellTemplate( MyTemplate )应用于DataGrid中具有特定类型( MyType )的所有列。

由于DataTable的列数动态,我无法禁用AutoGenerateColumns并在WPF中手动定义DataGridTemplateColumns

这是我在WPF中的DataTable

<DataGrid HeadersVisibility="Column" VerticalScrollBarVisibility="Visible" CanUserAddRows="False"
 IsSynchronizedWithCurrentItem="False" FontSize="12"  BorderThickness="0,1,0,0" RenderTransformOrigin="0.5,0.5"
 ItemsSource="{Binding MyDataTable}" AutoGenerateColumns="True" AutoGeneratingColumn="GeneratingColumnEvent"/>

我要分配的DataTemplateUserControl's资源字典中定义(在明确定义的DataGridTemplateColumn中使用时有效。)

<UserControl.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <SharedResourceDictionary Source="{Resources Directory}/MyTemplates.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
  </ResourceDictionary>
</UserControl.Resources>

我的 AutoGenerateColumn 事件定义如下:

private void GeneratingColumnEvent(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            if (e.PropertyType == typeof (MyType))
            {
                var newCol = new DataGridCandidateTemplateColumn
                {
                    CellTemplate = (DataTemplate) FindResource("MyTemplate"),
                    ColumnName = e.PropertyName,
                };
                e.Column = newCol;
                e.Column.Header = e.PropertyName;
            }
        }

使用如下定义的自定义DataGridCandidateTemplateColumn类:

class DataGridCandidateTemplateColumn : DataGridTemplateColumn
    {
        public string ColumnName { get; set; }

        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            // The DataGridTemplateColumn uses ContentPresenter with your DataTemplate.
            ContentPresenter cp = (ContentPresenter)base.GenerateElement(cell, dataItem);
            // Reset the Binding to the specific column. The default binding is to the DataRowView.
            if (cp != null)
                BindingOperations.SetBinding(cp, ContentPresenter.ContentProperty, new Binding(this.ColumnName));
            return cp;
        }
    }

如果我不尝试应用模板,该列将使用 MyType toString 表示。如果我像上面那样应用模板,则列的单元格中不会显示任何内容。我错过了什么?

2 个答案:

答案 0 :(得分:0)

通过使用TemplateColumn,您有点想要实现的目标有点不清楚。如果它只是用于格式化,那么您可以添加ResourceDictionary文件并在Windows XAML中引用它,如下例所示:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:sys="clr-namespace:System;assembly=mscorlib">
....

        <Setter Property="Margin" Value="0,0,0,3" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="FontSize" Value="{StaticResource somevalue}"  />
        <Setter Property="GridLinesVisibility" Value="All"/>
        <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource Somevalue}" />
        <Setter Property="VerticalGridLinesBrush" Value="{StaticResource SomeValue}" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Foreground" Value="Transparent" />
        <Setter Property="VerticalAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />

    <Style TargetType="DataGridColumnHeader">
        <Setter Property="Background" Value="{StaticResource ColumnHeaderBackgroundColor}"/>
        <Setter Property="Foreground" Value="{StaticResource ColumnHeaderForegroundColor}"/>
        <Setter Property="BorderBrush" Value="{StaticResource ColorBorderColumnHeader}" />
        <Setter Property="BorderThickness" Value="1,0,0,0"/>
        <Setter Property="Margin" Value="0,0,5,0"/>
        <Setter Property="Padding" Value="6,6,10,6"/>
        <Setter Property="Cursor" Value="Hand"/>
    </Style>

    <Style TargetType="DataGridRowHeader">
        <Setter Property="Visibility" Value="Collapsed"/>
        <Setter Property="Width" Value="0"/>
    </Style>

    <Style TargetType="DataGridRow">
        <Setter Property="Foreground" Value="{StaticResource GridFontColor}" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Style.Triggers>
            <Trigger Property="DataGridRow.IsSelected" Value="True">
            </Trigger>
        </Style.Triggers>
    </Style>

    <Style TargetType="DataGridCell">
        <Setter Property="Padding" Value="4,4,2,4"/>
        <Setter Property="Margin" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Border Padding="{TemplateBinding Padding}" 
                                    BorderBrush="{TemplateBinding BorderBrush}" 
                                    BorderThickness="{TemplateBinding BorderThickness}" 
                                    Background="{TemplateBinding Background}" 
                                    SnapsToDevicePixels="True">
                        <ContentPresenter SnapsToDevicePixels="True"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

否则,请使用GeneratingColumnEvent并设置Columns&#39;个别属性,例如widthString格式等

private void GeneratingColumnEvent(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    try
    {
        //Modify Columns names in Header, and apply proper String Format if needed
        // Collapse the ID column
        if (e.Column.Header.ToString() == "ID")
        { e.Column.Visibility = Visibility.Collapsed; }

        // Item
        else if (e.Column.Header.ToString() == "Item")
        { e.Column.Width = new DataGridLength(4.5, DataGridLengthUnitType.Star); }

        // Price
        if (e.Column.Header.ToString() == "Price")
        {
            e.Column.Header = "Px";
            (e.Column as DataGridTextColumn).Binding.StringFormat = "C2";
            e.Column.Width = new DataGridLength(1.7, DataGridLengthUnitType.Star);
        }
   }
    catch { }
}

答案 1 :(得分:0)

回答我自己的问题。我道歉,因为我的解决方案对每个人都不起作用。

我必须使用动态列数的原因是因为列数为3 + 5n,其中n是我的数据表中包含的数据类别数。

我能够利用这些数据(以下更多内容)使我能够禁用AutoGenerateColumns并将列定义为另一个事件的一部分(使用循环生成{{1} }类别)。通过能够定义每个列,我能够在不依赖5n的情况下分配我的模板来确定正确的模板。

我没有将我的数据网格绑定到我预先处理我的数据以包含DataGridAutoGeneratingColumnEventArgs列的数据表,而是用自定义类包装数据的3 + 5n部分。我还在一个类中包装了每一行,并使datagrid使用这些类的List作为其5n

这允许我创建列作为datagrid初始化过程的一部分。在为数据网格的ItemSource部分定义列时,我使用了这样的转换器:

列定义:

5n

转换器定义:

private void GenerateColumnEvent(object sender, EventArgs e)
{
    var table = sender as DataGrid;
    var context = table.DataContext 

    //Regular column definitions

    foreach(var category in context.CategoryIDList)
    {
        var binding = new Binding("CategoryWrapper")
        {
            Converter = new FindCategoryProperty(),
                ConverterParameter = new Tuple<categoryID, string>(category, "Property1")
        };
        var column = new DataGridTextColumn
        {
            Binding = binding,
            //Other column defining things (templates, headers, etc)
        };
        table.Columns.Add(column);

        //More column definitions
    }
}