【问题标题】:Merging cells in WPF DataGrid vertically垂直合并WPF DataGrid中的单元格
【发布时间】:2016-09-28 12:50:32
【问题描述】:

我想在 WPF 中创建一个DataGrid,其中一些单元格将“合并在一起”,如果它们相似的话。

例子:

+---------+------+-----+
| Country | Name | Age |
+---------+------+-----+
|         | Lisa | 24  |
+         +------+-----+
| Danmark |  Per | 32  |
+         +------+-----+
|         | Hans | 33  |
+---------+------+-----+
| Germany | Mick | 22  |
+---------+------+-----+

有没有什么方法可以通过绑定使用DataGrid 来实现这一点?

非常感谢。

【问题讨论】:

  • 看起来你不需要合并,而是分组数据。
  • 谷歌-fu! Thisthat.
  • 是的,这是可能的,而且非常简单。过一段时间我会发布的。
  • @tym32167 一直在研究这个。到目前为止,还没有发现任何有用的东西可以使 DataGrid 看起来像我想要的那样。
  • @Kilazu“这个”我已经准备好了。与我想要实现的目标完全不同。 “那个”会给我结果,但我希望有一种更简单的方法我错过了。无论如何,谢谢。

标签: c# wpf datagrid


【解决方案1】:

这种情况的诀窍是使用在CollectionViewSource 中形成的Groups 作为DataGridItemsSource。并且,使用DataGrid 本身作为CellTemplateColumn

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

这应该让你开始。

输出:

【讨论】:

  • 非常感谢您的回答,这正是我想要的。我看不到我应该如何将对象添加到绑定的 ItemsSource,你能解释一下吗?
  • @nickosv 找不到你
  • 好的,嗯..如何将对象添加到绑定的集合中?
  • 你不应该。因为分组是在您处理完数据后完成的。但这仍然是可能的。更具体的你的要求,会看到它。
  • 我还要如何显示“丹麦”、“罗伯特”等。我只想知道,您如何将数据“插入”到 DataGrid 中显示的集合中,我想不出自己解决:)
【解决方案2】:

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

C# 代码 - 结构化数据分为三个类。 (移除构造函数以减少代码行

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

注意:此解决方案实际上并不合并单元格,而是创建这样的视觉 效果。你可以试试这个。 Demo 使用两个 DataGrid 控件。 增加第一个DataGrid的行高以创建合并单元格效果。

替代方案: ReoGrid 是 MS Excel 兼容控件,支持 merge/unmerge 单元格功能,如 Excel。 ReoGrid 声称是免费和开源的。它不支持数据绑定,但它有support for DataTable

【讨论】:

    猜你喜欢
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2019-11-26
    • 1970-01-01
    • 2011-07-23
    相关资源
    最近更新 更多