Вопрос:
Я хочу сделать DataGrid в WPF, где некоторые из ячеек будут “сливаться вместе”, если они похожи.
Пример:
+———+——+——+ | Country | Name | Age | +———+——+——+ | | Lisa | 24 | + +——+——+ | Danmark | Per | 32 | + +——+——+ | | Hans | 33 | +———+——+——+ | Germany | Mick | 22 | +———+——+——+
Есть ли способ достичь этого, используя DataGrid используя привязку?
Заранее большое спасибо.
Лучший ответ:
Извините, все наладилось с другими вещами.
Трюк к таким сценариям заключается в использовании Groups сформированных в CollectionViewSource в качестве ItemsSource DataGrid. И используйте сам DataGrid как CellTemplate of Column.
Xaml
<Window.Resources> <CollectionViewSource x:Key=»CvsKey»> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName=»Country»/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <Grid> <DataGrid x:Name=»dg» Loaded=»dg_Loaded» HorizontalScrollBarVisibility=»Disabled» HeadersVisibility=»All» Grid.Column=»0″ RowHeaderWidth=»0″ CanUserAddRows=»False» AutoGenerateColumns=»False» VerticalContentAlignment=»Center» HorizontalContentAlignment=»Center»> <DataGrid.Columns> <DataGridTemplateColumn Header=»Country» Width=»75″> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <TextBlock VerticalAlignment=»Center» Text=»{Binding Name}»/> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header=»Name» Width=»75″> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <DataGrid ItemsSource=»{Binding Items}» IsReadOnly=»True» AutoGenerateColumns=»False» HeadersVisibility=»None»> <DataGrid.Columns> <DataGridTemplateColumn Width=»*»> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text=»{Binding Name}»/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>
DataGrid.Loaded event
private void dg_Loaded(object sender, RoutedEventArgs e) { var groups = (this.Resources[«CvsKey»] as CollectionViewSource).View.Groups; dg.ItemsSource = groups; }
Это должно заставить вас начать.
Вывод:
Ответ №1
Я создал демонстрационный проект на github.com
Вывод:
XAML-код: сетка с двумя столбцами и каждая из которых содержит DataGrid
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=»Auto» /> <ColumnDefinition Width=»Auto»/> </Grid.ColumnDefinitions> <DataGrid Name=»basketNameDataGrid» AutoGenerateColumns=»False» CanUserResizeRows=»False» CanUserAddRows=»False»> <DataGrid.RowStyle> <Style TargetType=»DataGridRow»> <Setter Property=»Height» Value=»{Binding RowHeight}»></Setter> </Style> </DataGrid.RowStyle> <DataGrid.Columns> <DataGridTemplateColumn Header=»Basket»> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text=»{Binding Name}» VerticalAlignment=»Center»/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> <DataGrid Name=»itemDataGrid» Grid.Column=»1″ AutoGenerateColumns=»False» HeadersVisibility=»Column» CanUserResizeRows=»False» CanUserAddRows=»False»> <DataGrid.RowStyle> <Style TargetType=»DataGridRow»> <Setter Property=»Height» Value=»20″></Setter> </Style> </DataGrid.RowStyle> <DataGrid.Columns> <DataGridTemplateColumn Header=»Item Name»> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text=»{Binding Name, Mode = OneWay}»/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header=»Price» Binding=»{Binding Price, Mode = OneWay}» CanUserSort=»False»></DataGridTextColumn> </DataGrid.Columns> </DataGrid> </Grid>
Код С#. Для структурирования данных существует три класса. (Удалены конструкторы для сокращения строк кода)
class Item { public Name {get;} public Price {set;} } class Basket : List<Item> { public Name {get;} } class BasketCollection : List<Basket> { }
Код в MainWindow.cs – заполняет данные и назначает DataGrids.
public MainWindow() { InitializeComponent(); //// Get some data to show in View var baskets = GetData(); int rowHeight = 20; //// itemDataGrid row height is 20 in xaml //// Create a list of annonymous type with properties Name an RowHeight. //// RowHeight = Height of one row * number of items in current basket. var basketNameData = baskets.Select(x => new { Name = x.Name, RowHeight = rowHeight * x.Count }); //// Assign data to first DataGrid basketNameDataGrid.ItemsSource = basketNameData.ToList(); //// Get list of all Items in all baskets and assign as ItemsSource to second datagrid itemDataGrid.ItemsSource = baskets.SelectMany(basket => basket).ToList(); } /// <summary> /// Gets some data to bind to view /// </summary> /// <returns>Basket Collection</returns> private BasketCollection GetData() { var baskets = new BasketCollection(); var fruitBasket = new Basket(«Fruit»); fruitBasket.Add(new Item(«Alphonso Mango», 80)); fruitBasket.Add(new Item(«Nagpur Orange», 10)); fruitBasket.Add(new Item(«Dragon Fruit», 50)); var vegetableBasket = new Basket(«Vegetable»); vegetableBasket.Add(new Item(«Brinjal», 5)); vegetableBasket.Add(new Item(«Broccoli», 5)); vegetableBasket.Add(new Item(«Onion», 3)); baskets.Add(fruitBasket); baskets.Add(vegetableBasket); return baskets; }
Примечание. Это решение фактически не объединяет ячейки, а создает такой визуальный эффект. Вы можете попробовать это. Демо использует два элемента управления DataGrid. Высота строки первого DataGrid увеличивается для создания эффекта объединенной ячейки.
Альтернатива: ReoGrid – это совместимый с MS Excel элемент управления, который поддерживает функции merge/unmerge, такие как Excel. ReoGrid утверждает, что является свободным и открытым исходным кодом. Он не поддерживает привязку данных, но имеет поддержку DataTable.