WPF动态合并和拆分网格单元

时间:2015-02-16 17:35:44

标签: c# wpf

这个问题可能有点开放,但我正在寻找有关如何动态合并和分割网格单元的问题的建议。

所以目前我生成一个X行和Y列的网格,然后用StackPanel填充每个单元格。单击时,StackPanel会添加一个边框,并且会修改一个表示每个网格单元格的bool值的数组,以显示它已被单击。网格没有其他控件。这些都是在c#中以编程方式完成的,而不是在xaml中完成的。

我想要做的是通过点击按钮合并并拆分网格中的所选单元格(如果它们彼此相邻)。我发现没有办法轻易做到这一点,我想知道是否有人可以为这个问题推荐一个好方法。

我不依赖于我目前的方法,并且赞赏任何其他方法建议。

1 个答案:

答案 0 :(得分:2)

我刚刚在Github上发布了一个如何执行此操作的示例。

基本思想是使用最大行数和列数初始化网格,然后创建和删除单元格,同时根据需要修改其位置和跨度以填充网格。

以下是最相关的摘录:

初始化:(MainWindow.xaml.cs)

public MainWindow()
{
    InitializeComponent();

    var numRows = grid.RowDefinitions.Count;
    var numCols = grid.ColumnDefinitions.Count;

    for (int i = 0; i < numRows; i++)
    {
        for (int j = 0; j < numCols; j++)
        {
            var item = new DynamicGridItem(j, i);
            item.Merge += HandleMerge;
            item.Split += HandleSplit;
            grid.Children.Add(item);
            Grid.SetRow(item, i);
            Grid.SetColumn(item, j);
        }
    }
}

在这里,您可以看到我的单元格项是一个自定义UserControl类,其构造函数将两个整数作为X和Y网格坐标。然后可以使用这些坐标来简化网格行和列分配。在我的示例中,它们并不是绝对必要的,但如果存储/加载网格项并在其他代码模块中使用它们可能会有所帮助。

合并事件:

我的示例使用带有布尔事件参数的单个Merge事件来指示合并是向左还是向右。实际的事件处理程序只是确定是向左还是向右偏移,并将该信息以及源项传递给下面的HandleMergeOffset方法。

private void HandleMergeOffset(DynamicGridItem item, int offset)
{
    var otherItem = FindItemByXOffset(item, offset);
    if (otherItem == null)
    {
       return; // Nothing to do
    }

    otherItem.Merge -= HandleMerge;
    otherItem.Split -= HandleSplit;
    Grid.SetColumnSpan(item, Grid.GetColumnSpan(item) + Grid.GetColumnSpan(otherItem));
    grid.Children.Remove(otherItem);

    if (offset < 0) // Reposition item if merging left
    {
        Grid.SetColumn(item, otherItem.X);
        item.X = otherItem.X;
    }
}

你可能写一个比我更好的FindItem方法。基本思路是找到要删除的邻居,展开当前项目以包括原始列跨度,从已删除项目中取消挂钩事件,当然还要从网格中删除它。

拆分事件:

由于我们删除了Merge上的某个项目,因此我们会在Split上创建一个新项目。我决定不打扰SplitLeftSplitRight指定。此代码将始终在原始单元格的最左侧索引处创建最小单元格,并将其余部分向右推。

private void HandleSplit(object sender, EventArgs e)
{
    var item = (DynamicGridItem)sender;
    var itemColSpan = Grid.GetColumnSpan(item);
    if (itemColSpan < 2)
    {
        return; // Nothing to do
    }

    var newItem = new DynamicGridItem(item.X, item.Y);
    newItem.Merge += HandleMerge;
    newItem.Split += HandleSplit;
    grid.Children.Add(newItem);
    Grid.SetColumn(newItem, newItem.X);
    Grid.SetRow(newItem, newItem.Y);
    Grid.SetColumn(item, item.X + 1);
    Grid.SetColumnSpan(item, itemColSpan - 1);
    item.X += 1;
}

请注意,这不会尝试将单个单元格拆分为半个单元格(这样我们就不会改变原始网格或处理子网格)。如果您需要任意动态网格行为,您将想要寻找其他地方。