【问题标题】:Custom cell class in data grid数据网格中的自定义单元格类
【发布时间】:2018-11-14 15:34:23
【问题描述】:

我创建了一个源自DataGrid 的矩阵控件,它应该能够在单元格中显示复杂类型。然后,这些复杂类型应通过模板设置样式。

使用AutoGenerateColumns 时,DataGrid 将根据分配给ItemsSource 的列表类型自动创建列和单元格类型。

我想替换网格的行、列和单元格类型以执行自定义操作和绑定到它的视图模型。我已经能够创建自定义行和列。有什么方法可以从DataGridCell 派生并让数据网格使用该类型而不是默认类型?

我查看了 .net 源代码,发现该行使用 DataGridCellsPresenter 创建单元格,但该属性不可访问。

public class MatrixControl : DataGrid
{
  public static readonly DependencyProperty COLUMN_HEADER_TEMPLATE_PROPERTY = DependencyProperty.Register(nameof(ColumnHeaderTemplate), typeof(DataTemplate), typeof(MatrixControl), new PropertyMetadata(default(object)));

  public DataTemplate ColumnHeaderTemplate { get { return (DataTemplate)GetValue(COLUMN_HEADER_TEMPLATE_PROPERTY); } set { SetValue(COLUMN_HEADER_TEMPLATE_PROPERTY, value); } }

  private MatrixViewModel ViewModel { get { return DataContext as MatrixViewModel; } }

  public MatrixControl()
  {
    DataContextChanged += OnDataContextChanged;
    SelectionMode = DataGridSelectionMode.Extended;
    SelectionUnit = DataGridSelectionUnit.CellOrRowHeader;
    AutoGenerateColumns = true;
  }

  private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
  {
    ItemsSource = ViewModel.Rows.Select(c => new Row(c, ViewModel));
  }

  protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
  {
    e.Cancel = true;
    Columns.Clear();
    foreach (var column in ViewModel.Columns)
    {
      Columns.Add(new MatrixColumn(column)
      {
        HeaderTemplate = ColumnHeaderTemplate
      });
    }
  }
}

class MatrixColumn : DataGridTemplateColumn
{
  public object Value { get; }

  public MatrixColumn(object value)
  {
    Value = value;
  }
}

class Row
{
  public object Value { get; }

  public Row(object value)
  {
    Value = value;
  }
}

class MatrixViewModel
{
  public IEnumerable<object> Columns { get; set; }
  public IEnumerable<object> Rows { get; set; }
}

更新:尝试替换DataGridCellsPresenter

// in data grid class
protected override DependencyObject GetContainerForItemOverride()
{
  return new MatrixRow();
}

class MatrixRow : DataGridRow
{       
  public MatrixRow()
  {
    var cellPresenterProperty = GetType().GetProperty("CellsPresenter", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty);
    cellPresenterProperty.SetValue(this, new MatrixCellPresenter());
  }
}

class MatrixCellPresenter : DataGridCellsPresenter
{
  protected override DependencyObject GetContainerForItemOverride()
  {
    // won't get called, the presenter is overriden by the internal one
    return new MatrixCell();
  }
}

【问题讨论】:

  • DataGridRow 的默认模板使用DataGridDetailsPresenter 创建单元格。您可以覆盖DataGridGetContainerForItemOverride() 方法以返回自定义行容器,然后实现您自己的自定义DataGridDetailsPresenter。不过,这将需要相当多的努力。
  • 我试过已经从DataGridRow 派生但又一次,我不能覆盖DataGridDetailsPresenter,它隐藏在内部字段中。看来内部DataGridDetailsPresenter实例会自动将自身应用到所有行,所以通过反射在行上设置它是没有意义的
  • 您仍然可以创建自定义DataGridDetailsPresenter。或自定义DataGridRow
  • 我当然可以创建一个,但我如何告诉数据网格使用它?
  • 我更新了问题。查看DataGrid 源代码时,我无法弄清楚DataGridCellsPresenter 是如何以及在何处被实例化的......

标签: c# wpf datagrid


【解决方案1】:

我已经找到解决这个post问题的方法。

到目前为止,问题中的代码很好,唯一需要做的就是覆盖 xaml 中的 MatrixRow 模板。为了完整起见,我发布了另一个问题的 xaml 代码:

<Style TargetType="{x:Type local:MatrixRow}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:MatrixRow}">
        <Border x:Name="DGR_Border"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}"
                      SnapsToDevicePixels="True">
          <SelectiveScrollingGrid>
            <SelectiveScrollingGrid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </SelectiveScrollingGrid.ColumnDefinitions>
            <SelectiveScrollingGrid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </SelectiveScrollingGrid.RowDefinitions>

            <!-- Make sure to register your custom DataGridCellsPresenter here as following -->

            <local:MatrixCellPresenter Grid.Column="1"
                              ItemsPanel="{TemplateBinding ItemsPanel}"
                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
            <DataGridDetailsPresenter Grid.Column="1"
                                Grid.Row="1"
                                Visibility="{TemplateBinding DetailsVisibility}"
                                SelectiveScrollingGrid.SelectiveScrollingOrientation=
                                  "{Binding AreRowDetailsFrozen, 
                                  ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical},
                                  Converter={x:Static DataGrid.RowDetailsScrollingConverter}, 
                                  RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
            <DataGridRowHeader Grid.RowSpan="2"
                             SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
                             Visibility="{Binding HeadersVisibility, 
                              ConverterParameter={x:Static DataGridHeadersVisibility.Row}, 
                              Converter={x:Static DataGrid.HeadersVisibilityConverter}, 
                              RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
          </SelectiveScrollingGrid>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

【讨论】:

    猜你喜欢
    • 2015-12-13
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    • 2012-07-10
    相关资源
    最近更新 更多