#wpf #datagrid #grouping
#wpf #datagrid #группировка
Вопрос:
Возможно ли это сделать в WPF datagrid :
|-------------- A header------------|---------------B Header---------------|
|-----A1Header----|----A2Header-----|-----B1Header-----|-----B2Header------|
|-----A1Data------|----A2 Data------|-----B1 Data------|-----B2 Data-------|
|-----A1Data------|----A2 Data------|-----B1 Data------|-----B2 Data-------|
Спасибо.
Комментарии:
1. Уверен, что об этом спрашивали раньше…
2. Я пытался найти это, но смог найти вопрос только с помощью JS, а не WPF. Если да, не могли бы вы указать мне на вопрос, пожалуйста?
3. Я не могу, поскольку не могу его найти (если он когда-либо существовал), полагаю, это не имеет значения.
Ответ №1:
Этот поток может помочь вам достичь того, что вы пытаетесь сделать.
Он не получает функциональность непосредственно из DataGrid, но вместо этого DataGrid заключен в обычную сетку и использует связанные столбцы (с несколькими столбцами) для добавления суперзаголовков.
Надеюсь, есть хороший простой способ сделать это непосредственно из DataGrid, но если нет, возможно, это будет приемлемым обходным путем для вас.
Комментарии:
1. Я попробую это как можно скорее… Это странно, но если это сработает, я полностью за.
2. Сработало! Мне пришлось включить мою сетку в scrollviewer, потому что она занимает больше ширины окна, но все равно приятная.
3. Очень приятно. Именно то, что я искал
Ответ №2:
Я могу предложить три решения проблемы группировки столбцов.
Решение 1
Используя обычную группировку через ICollectionView
из исходной коллекции. Эти группы являются вертикальными, что означает, что они используют одни и те же столбцы.
Решение 2
Создайте вложенный источник данных. Идея заключается в том, что каждый столбец привязывается к отдельному набору данных, который отображается с помощью a, DataGrid
который добавляется к столбцу DataGridTemplateColumn
. Это DataGrid
для каждой группы столбцов. Недостатком этого решения является то, что ограничения для структуры данных очень жесткие. Не поддерживается DataTable и нет автоматической генерации столбцов. Усилия возрастают, если разрешена сортировка или изменение порядка столбцов. но для простого отображения сгруппированной таблицы этого решения достаточно.
Пример использования
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<!-- Toplevel DataGrid that displays the column group headers -->
<DataGrid ItemsSource="{Binding Rows}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<!-- The grouped column definitions -->
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=Items[0].Columns[0].GroupHeader}"></TextBlock>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type local:DataGridRowItem}">
<DataGrid ItemsSource="{Binding Columns[0].TableData}"
local:DataGridHelper.IsSynchronizeSelectedRowEnabled="True"
local:DataGridHelper.SynchronizeGroupKey="A"
RowHeaderWidth="0"
BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type local:DataGridRowItem}">
<TextBox />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=Items[0].Columns[1].GroupHeader}"></TextBlock>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type local:DataGridRowItem}">
<DataGrid ItemsSource="{Binding Columns[1].TableData}"
local:DataGridHelper.IsSynchronizeSelectedRowEnabled="True"
local:DataGridHelper.SynchronizeGroupKey="A"
RowHeaderWidth="0"
BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type local:DataGridRowItem}">
<TextBox />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
Рекомендуется отключить модификации таблицы с помощью DataGrid
. Улучшить внешний вид, например, центрировать имена групп или переопределить DataGridRow
шаблон, чтобы добавить подсветку строк для несфокусированных сеток, довольно просто.
Пример реализации
Структура данных для вложенных таблиц:
DataGridRowItem.cs
Корневой элемент. Элемент с одной строкой для верхнего уровня DataGrid
это отобразит заголовки группы столбцов. Группа столбцов для каждого DataGridColumnItem
.
public class DataGridRowItem
{
public List<DataGridColumnItem> Columns { get; set; }
}
DataGridColumnItem.cs
Каждый DataGridColumnItem
создаст группу столбцов.
public class DataGridColumnItem
{
public string GroupHeader { get; set; }
public List<Appointment> TableData { get; set; }
}
Appointment.cs
Фактическая модель данных, которая отображается в группе DataGrid
.
public class Appointment
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
ViewModel.cs
public class TestViewModel : ViewModel
{
public List<DataGridRowItem> Rows { get; }
public ViewModel()
{
this.GroupingRow = new List<DataGridRowItem>
{
// The single row for the grouping top level DataGrid
new DataGridRowItem()
{
Columns = new List<DataGridColumnItem>()
{
// First column group
new DataGridColumnItem()
{
GroupHeader = "Group 1",
TableData = new List<Appointment>
{
new Appointment() { Start = DateTime.Now.AddDays(1), End = DateTime.Now.AddDays(2) },
new Appointment() { Start = DateTime.Now.AddDays(5), End = DateTime.Now.AddDays(6) }
}
},
// Second column group
new DataGridColumnItem()
{
GroupHeader = "Group 2",
TableData = new List<Appointment>
{
new Appointment() { Start = DateTime.Now.AddDays(3), End = DateTime.Now.AddDays(4) },
new Appointment() { Start = DateTime.Now.AddDays(7), End = DateTime.Now.AddDays(8) }
}
}
}
}
};
}
}
DataGridHelper.cs
Прикрепленное поведение, которое помогает синхронизировать выбранную строку в нескольких DataGrid
экземплярах. поведение изначально было написано для разных задач, но может быть повторно использовано и в этом сценарии. Это позволяет создавать группы синхронизации DataGrid
элементов.
public class DataGridHelper : DependencyObject
{
public static object GetSynchronizeGroupKey(DependencyObject attachedElement)
=> (object)attachedElement.GetValue(SynchronizeGroupKeyProperty);
public static void SetSynchronizeGroupKey(DependencyObject attachedElement, object value)
=> attachedElement.SetValue(SynchronizeGroupKeyProperty, value);
public static readonly DependencyProperty SynchronizeGroupKeyProperty = DependencyProperty.RegisterAttached(
"SynchronizeGroupKey",
typeof(object),
typeof(DataGridHelper),
new PropertyMetadata(default(object), OnSynchronizeGroupKeyChanged));
public static bool GetIsSynchronizeSelectedRowEnabled(DependencyObject attachedElement)
=> (bool)attachedElement.GetValue(IsSynchronizeSelectedRowEnabledProperty);
public static void SetIsSynchronizeSelectedRowEnabled(DependencyObject attachedElement, bool value)
=> attachedElement.SetValue(IsSynchronizeSelectedRowEnabledProperty, value);
public static readonly DependencyProperty IsSynchronizeSelectedRowEnabledProperty = DependencyProperty.RegisterAttached(
"IsSynchronizeSelectedRowEnabled",
typeof(bool),
typeof(DataGridHelper),
new PropertyMetadata(default(bool), OnIsSynchronizeSelectedRowEnabledChanged));
private static Dictionary<object, IList<WeakReference<DataGrid>>> DataGridTable { get; } = new Dictionary<object, IList<WeakReference<DataGrid>>>();
private static void OnIsSynchronizeSelectedRowEnabledChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
{
if (attachingElement is not DataGrid dataGrid)
{
throw new ArgumentException($"Attaching element must of type {typeof(DataGrid)}.", nameof(attachingElement));
}
if ((bool)e.NewValue)
{
RegisterDataGridForSelectedItemSynchronization(dataGrid);
}
else
{
UnregisterDataGridForSelectedItemSynchronization(dataGrid);
}
}
private static void RegisterDataGridForSelectedItemSynchronization(DataGrid dataGrid)
=> WeakEventManager<DataGrid, SelectionChangedEventArgs>.AddHandler(dataGrid, nameof(DataGrid.SelectionChanged), SynchronizeSelectedItem_OnSelectionChanged);
private static void UnregisterDataGridForSelectedItemSynchronization(DataGrid dataGrid)
=> WeakEventManager<DataGrid, SelectionChangedEventArgs>.RemoveHandler(dataGrid, nameof(DataGrid.SelectionChanged), SynchronizeSelectedItem_OnSelectionChanged);
private static void OnSynchronizeGroupKeyChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
{
if (attachingElement is not DataGrid dataGrid)
{
throw new ArgumentException($"Attaching element must of type {typeof(DataGrid)}.", nameof(attachingElement));
}
if (e.NewValue == null)
{
throw new ArgumentNullException($"{null} is not a valid value for the attached property {nameof(SynchronizeGroupKeyProperty)}.", nameof(e.NewValue));
}
if (!DataGridTable.TryGetValue(e.NewValue, out IList<WeakReference<DataGrid>>? dataGridGroup))
{
dataGridGroup = new List<WeakReference<DataGrid>>();
DataGridTable.Add(e.NewValue, dataGridGroup);
}
dataGridGroup.Add(new WeakReference<DataGrid>(dataGrid));
}
private static void SynchronizeSelectedItem_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var synchronizationSourceDataGrid = sender as DataGrid;
var synchronizationSourceDataGridGroupKey = GetSynchronizeGroupKey(synchronizationSourceDataGrid);
if (!DataGridTable.TryGetValue(synchronizationSourceDataGridGroupKey, out IList<WeakReference<DataGrid>> dataGridGroup))
{
return;
}
var selectedIndices = synchronizationSourceDataGrid.SelectedItems
.Cast<object>()
.Select(synchronizationSourceDataGrid.Items.IndexOf)
.ToList();
foreach (WeakReference<DataGrid> dataGridReference in dataGridGroup)
{
if (!dataGridReference.TryGetTarget(out DataGrid dataGrid)
|| dataGrid == synchronizationSourceDataGrid
|| dataGrid.Items.Count == 0)
{
continue;
}
UnregisterDataGridForSelectedItemSynchronization(dataGrid);
dataGrid.SelectedItems.Clear();
foreach (int selectedItemIndex in selectedIndices)
{
var selectedItem = dataGrid.Items[selectedItemIndex];
dataGrid.SelectedItems.Add(selectedItem);
}
RegisterDataGridForSelectedItemSynchronization(dataGrid);
}
}
}
Решение 3
Более эффективным решением является реализация пользовательского элемента управления. Таким образом, например, изменять порядок / размер столбцов, добавлять / удалять строки и настраивать действительно удобно.
Пользовательский элемент управления GroupingDataGrid
в основном обертывает пользовательский DataGrid
в Grid
.
Это решение поддерживает автоматическую генерацию, а также явные определения столбцов. Группы столбцов и отдельные столбцы могут быть изменены.
Тот DataGrid
, который размещен на GroupingDataGrid
, может использоваться без каких-либо ограничений. Макет чистый, и определение групп столбцов (с использованием GroupDefinition
в стиле определений сетки) довольно удобно.
Чтобы настроить заголовки группы, определите a, Style
предназначенный GroupingDataGridHeader
(который является a ContenControl
).
GroupingDataGrid
Это существующий элемент управления из моей библиотеки. Я удалил некоторый код, в основном функции настройки, такие как создание шаблонов, из исходных текстов, чтобы сохранить сообщение как можно более кратким.
Пример использования
<local:GroupingDataGrid>
<local:GroupingDataGrid.GroupDefinitions>
<!-- Group from column 0 to 3 -->
<local:GroupDefinition ColumnSpan="4"
Header="Person" />
<!-- Second group from column 4 to 5 -->
<local:GroupDefinition Column="4"
ColumnSpan="2"
Header="Numbers" />
<!-- Remaining columns are automatically added
to a common unnamed group -->
</local:GroupingDataGrid.GroupDefinitions>
<!-- Define DataGrid as usual -->
<DataGrid ItemsSource="{Binding DataGridItems}" />
</local:GroupingDataGrid>
Исходный код
GroupingDataGrid.cs
[ContentProperty(nameof(GroupingDataGrid.DataGrid))]
public class GroupingDataGrid : Control
{
public GroupDefinitionCollection GroupDefinitions
{
get => (GroupDefinitionCollection)GetValue(GroupDefinitionsProperty);
set => SetValue(GroupDefinitionsProperty, value);
}
public static readonly DependencyProperty GroupDefinitionsProperty = DependencyProperty.Register(
"GroupDefinitions",
typeof(GroupDefinitionCollection),
typeof(GroupingDataGrid),
new PropertyMetadata(default));
public DataGrid DataGrid
{
get { return (DataGrid)GetValue(DataGridProperty); }
set { SetValue(DataGridProperty, value); }
}
public static readonly DependencyProperty DataGridProperty = DependencyProperty.Register(
"DataGrid",
typeof(DataGrid),
typeof(GroupingDataGrid),
new PropertyMetadata(default(DataGrid), OnDataGridChanged));
static GroupingDataGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(GroupingDataGrid), new FrameworkPropertyMetadata(typeof(GroupingDataGrid)));
}
private static void OnDataGridChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
=> (d as GroupingDataGrid).OnDataGridChanged(e.OldValue as DataGrid, e.NewValue as DataGrid);
private bool IsDataGridLayoutDirty { get; set; }
private Grid GroupHost { get; }
private Dictionary<Thumb, GroupingDataGridHeader> ThumbToGroupingDataGridHeaderTable { get; }
private Dictionary<GroupDefinition, GroupingDataGridHeader> GroupDefinitionToGroupingDataGridHeaderTable { get; }
public GroupingDataGrid()
{
this.GroupDefinitions = new GroupDefinitionCollection();
this.ThumbToGroupingDataGridHeaderTable = new Dictionary<Thumb, GroupingDataGridHeader>();
this.GroupDefinitionToGroupingDataGridHeaderTable = new Dictionary<GroupDefinition, GroupingDataGridHeader>();
this.GroupHost = new Grid();
this.GroupHost.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
this.GroupHost.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var contentHost = GetTemplateChild("PART_DataGridHost") as ContentPresenter;
if (contentHost != null)
{
contentHost.Content = this.GroupHost;
}
}
protected virtual void OnDataGridChanged(DataGrid oldDataGrid, DataGrid newDataGrid)
{
if (oldDataGrid != null)
{
this.GroupHost.Children.Remove(oldDataGrid);
oldDataGrid.ColumnDisplayIndexChanged -= OnColumnOrderChanged;
oldDataGrid.AutoGeneratedColumns -= OnDataGridAutoGeneratedColumns;
}
if (newDataGrid == null)
{
return;
}
this.IsDataGridLayoutDirty = true;
this.GroupHost.Children.Add(this.DataGrid);
newDataGrid.ColumnDisplayIndexChanged = OnColumnOrderChanged;
if (newDataGrid.AutoGenerateColumns amp;amp; !newDataGrid.IsLoaded)
{
newDataGrid.AutoGeneratedColumns = OnDataGridAutoGeneratedColumns;
}
else
{
CreateVisualTree();
}
}
private void OnColumnOrderChanged(object? sender, DataGridColumnEventArgs e)
=> CreateVisualTree();
private void OnDataGridAutoGeneratedColumns(object sender, EventArgs e)
=> CreateVisualTree();
private void CreateVisualTree()
{
CreateGroups();
if (this.IsDataGridLayoutDirty)
{
LayoutDataGrid();
}
}
private void CreateGroups()
{
this.ThumbToGroupingDataGridHeaderTable.Clear();
this.GroupDefinitionToGroupingDataGridHeaderTable.Clear();
ClearGroupHost();
AddRowHeaderColumnGroup();
List<DataGridColumn> sortedColumns = this.DataGrid.Columns
.OrderBy(column => column.DisplayIndex)
.ToList();
int ungroupedColumnCount = sortedColumns.Count - this.GroupDefinitions.Sum(definition => definition.ColumnSpan);
bool hasUngroupedColumns = ungroupedColumnCount > 0;
for (int groupIndex = 0; groupIndex < this.GroupDefinitions.Count; groupIndex )
{
GroupDefinition group = this.GroupDefinitions[groupIndex];
int groupHeaderColumnIndex = groupIndex 1;
AddGridColumn();
AddGroupHeader(group, groupHeaderColumnIndex, sortedColumns);
if (groupHeaderColumnIndex > 1)
{
GroupDefinition previousGroup = this.GroupDefinitions[groupIndex - 1];
AddColumnGrippers(previousGroup, groupHeaderColumnIndex - 1);
}
}
if (hasUngroupedColumns)
{
AddGroupForRemainingColumns();
}
}
private void AddGroupForRemainingColumns()
{
AddGridColumn(false);
AddGroupHeader(null, this.GroupHost.ColumnDefinitions.Count - 1, new List<DataGridColumn>());
if (this.GroupDefinitions.Any())
{
GroupDefinition previousGroup = this.GroupDefinitions.Last();
AddColumnGrippers(previousGroup, this.GroupDefinitions.Count);
}
}
private void CreateColumnGroupHeaderBinding(IList<DataGridColumn> sortedColumns, GroupingDataGridHeader groupHeaderHost)
{
GroupDefinition group = groupHeaderHost.GroupDefinition;
var groupHeaderWidthMultiBinding = new MultiBinding
{
Mode = BindingMode.TwoWay,
Converter = new DataGridColumnRangeWidthToGroupHeaderWidthConverter(sortedColumns),
ConverterParameter = group
};
for (int columnIndex = group.Column; columnIndex < group.Column group.ColumnSpan; columnIndex )
{
DataGridColumn column = sortedColumns[columnIndex];
var widthBinding = new Binding(nameof(DataGridColumn.Width))
{
Mode = BindingMode.TwoWay,
Source = column
};
groupHeaderWidthMultiBinding.Bindings.Add(widthBinding);
}
groupHeaderHost.SetBinding(WidthProperty, groupHeaderWidthMultiBinding);
}
private GroupingDataGridHeader AddGroupHeader(GroupDefinition group, int groupHeaderColumnIndex, List<DataGridColumn> sortedColumns)
{
var groupHeaderHost = new GroupingDataGridHeader(group);
Grid.SetColumn(groupHeaderHost, groupHeaderColumnIndex);
Grid.SetRow(groupHeaderHost, 0);
this.GroupHost.Children.Add(groupHeaderHost);
if (group != null)
{
this.GroupDefinitionToGroupingDataGridHeaderTable.Add(group, groupHeaderHost);
if (sortedColumns.Any())
{
CreateColumnGroupHeaderBinding(sortedColumns, groupHeaderHost);
}
}
return groupHeaderHost;
}
private void AddGridColumn(bool isAutoWidth = true)
{
var gridColumnWidth = isAutoWidth
? GridLength.Auto
: new GridLength(1, GridUnitType.Star);
var groupHeaderHostColumnDefinition = new ColumnDefinition() { Width = gridColumnWidth };
this.GroupHost.ColumnDefinitions.Add(groupHeaderHostColumnDefinition);
}
private void AddColumnGrippers(GroupDefinition groupDefinition, int groupHeaderColumnIndex)
{
GroupingDataGridHeader groupHeaderHost = this.GroupDefinitionToGroupingDataGridHeaderTable[groupDefinition];
AddColumnGripper(groupHeaderColumnIndex, groupHeaderHost, true);
AddColumnGripper(groupHeaderColumnIndex 1, groupHeaderHost);
}
private void AddColumnGripper(int columnIndex, GroupingDataGridHeader groupHeader, bool isLeftColumnGripper = false)
{
var columnGripper = new Thumb()
{
HorizontalAlignment = isLeftColumnGripper
? HorizontalAlignment.Right
: HorizontalAlignment.Left,
};
columnGripper.DragDelta = OnGroupHeaderResizing;
this.ThumbToGroupingDataGridHeaderTable.Add(columnGripper, groupHeader);
Grid.SetColumn(columnGripper, columnIndex);
Grid.SetRow(columnGripper, 0);
this.GroupHost.Children.Add(columnGripper);
}
private void LayoutDataGrid()
{
Grid.SetColumnSpan(this.DataGrid, this.GroupHost.ColumnDefinitions.Count);
Grid.SetRow(this.DataGrid, 1);
this.IsDataGridLayoutDirty = false;
}
private void AddRowHeaderColumnGroup()
{
AddGridColumn();
GroupingDataGridHeader rowHeaderGroupHost = AddGroupHeader(null, 0, new List<DataGridColumn>());
var rowHeaderWidthBinding = new Binding(nameof(DataGrid.RowHeaderActualWidth))
{
Source = this.DataGrid
};
rowHeaderGroupHost.SetBinding(WidthProperty, rowHeaderWidthBinding);
}
private void ClearGroupHost()
{
for (int childIndex = this.GroupHost.Children.Count - 1; childIndex >= 0; childIndex--)
{
var child = this.GroupHost.Children[childIndex];
if (child != this.DataGrid)
{
this.GroupHost.Children.Remove(child);
}
}
}
private void OnGroupHeaderResizing(object sender, DragDeltaEventArgs e)
{
var thumb = sender as Thumb;
if (this.ThumbToGroupingDataGridHeaderTable.TryGetValue(thumb, out GroupingDataGridHeader groupingDataGridHeader))
{
groupingDataGridHeader.Width = e.HorizontalChange;
}
}
}
GroupingDataGridHeader.cs
public class GroupingDataGridHeader : ContentControl
{
public GroupDefinition GroupDefinition { get; }
public GroupingDataGridHeader() : this(new GroupDefinition())
{
}
public GroupingDataGridHeader(GroupDefinition groupDefinition)
{
this.GroupDefinition = groupDefinition;
this.Content = this.GroupDefinition?.Header ?? string.Empty;
}
static GroupingDataGridHeader()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(GroupingDataGridHeader), new FrameworkPropertyMetadata(typeof(GroupingDataGridHeader)));
}
}
GroupDefinition.cs
public class GroupDefinition : FrameworkContentElement
{
public int Column
{
get => (int)GetValue(ColumnProperty);
set => SetValue(ColumnProperty, value);
}
public static readonly DependencyProperty ColumnProperty = DependencyProperty.Register(
"Column",
typeof(int),
typeof(GroupDefinition),
new PropertyMetadata(default));
public int ColumnSpan
{
get => (int)GetValue(ColumnSpanProperty);
set => SetValue(ColumnSpanProperty, value);
}
public static readonly DependencyProperty ColumnSpanProperty = DependencyProperty.Register(
"ColumnSpan",
typeof(int),
typeof(GroupDefinition),
new PropertyMetadata(default));
public object Header
{
get => (object)GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
"Header",
typeof(object),
typeof(GroupDefinition),
new PropertyMetadata(default));
}
GroupDefinitionCollection.cs
public class GroupDefinitionCollection : Collection<GroupDefinition>
{ }
DataGridColumnRangeWidthToGroupHeaderWidthConverter.cs
public class DataGridColumnRangeWidthToGroupHeaderWidthConverter : IMultiValueConverter
{
private IList<DataGridColumn> DataGridColumns { get; }
public DataGridColumnRangeWidthToGroupHeaderWidthConverter(IList<DataGridColumn> dataGridColumns)
{
this.DataGridColumns = dataGridColumns;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
=> values.Cast<DataGridLength>().Sum(gridLength => gridLength.DisplayValue);
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
var groupDefinition = (GroupDefinition)parameter;
double currentGroupedColumnsWidth = this.DataGridColumns
.Skip(groupDefinition.Column)
.Take(groupDefinition.ColumnSpan)
.Select(column => column.Width.DisplayValue)
.Sum();
var result = new object[groupDefinition.ColumnSpan];
Array.Fill(result, Binding.DoNothing);
DataGridColumn lastGroupColumn = this.DataGridColumns[groupDefinition.Column groupDefinition.ColumnSpan - 1];
var newColumnWidth = new DataGridLength(lastGroupColumn.Width.DisplayValue (double)value - currentGroupedColumnsWidth, DataGridLengthUnitType.Pixel);
result[result.Length - 1] = newColumnWidth;
return resu<
}
}
Generic.xaml
<ResourceDictionary>
<Style TargetType="local:GroupingDataGrid">
<Style.Resources>
<Style TargetType="Thumb">
<Setter Property="Width"
Value="8" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Cursor"
Value="SizeWE" />
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="BorderThickness"
Value="0,0,1,0" />
<Setter Property="BorderBrush"
Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:GroupingDataGrid">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter x:Name="PART_DataGridHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:GroupingDataGridHeader">
<Setter Property="BorderThickness"
Value="0,0,1,0" />
<Setter Property="BorderBrush"
Value="Black" />
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:GroupingDataGridHeader">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Комментарии:
1. В этом коде мне не хватает GroupingDataGridHeader. Я слепой? Или я должен создавать это как часть моей реализации, чтобы посмотреть, как я хочу, чтобы группа столбцов выглядела?
2. Нет, вы были правы. Я имею в виду, что у вас хорошее зрение. Похоже, я забыл опубликовать этот класс. Я опубликую это позже, когда вернусь, и тогда дам вам знать. Извините. И спасибо, что рассказали мне.
3. Нет, спасибо за такое элегантное и обширное решение для командной строки. Мне нужно сделать что-то более сложное, чем позволяют многие более простые решения для этой проблемы.
4. Вы очень добры. Большое вам спасибо. Я добавил отсутствующий GroupingDataGridHeader.cs . Дайте мне знать, если вам нужна поддержка.
5. Я только что вернулся к этому проекту. У меня есть datagrid, который отображается правильно, но просто никогда не отображается внутри GroupingDataGrid. Глядя на код, я полагаю, что мне не хватает какого-либо шаблонного приложения для запуска GroupingDataGrid. OnApplyTemplate() (который подключил бы DataGrid к элементу шаблона ‘PART_DataGridHost’; вероятно, ContentPresenter?) Я собираюсь поиграть с попыткой создать для этого подходящий шаблон; дайте мне знать, если у вас есть образец, или если я чего-то не хватает.
Ответ №3:
Если можно оплатить, в Telerik RadGridView есть группы столбцов