• [C1] C1FlexGrid 行列增删&单元格合并拆分


    上一篇中实现了 C1FlexGrid的撤销还原功能,这篇是要仿 Excel 做一个行列删除以及单元格的自由合并拆分,楼主怕在原工程里复杂的说不清道不明,所以干脆提取出来做了一个 Demo 来说明实现过程,请指教了。

    一  前提概要

    C1FlexGrid 中自带的 AllowMerging 属性可以控制单元格的自动合并,条件是相邻单元格的内容相同,就自动合并。

    其中 Row 和 Column 还有 C1FlexGrid 本身均可设置 AllowMerging 属性,如果设置某行的 AllowMerging 属性为 true,即 _flex.Rows[i].AllowMerging = true; 则在 i 行内,如果相邻单元格内容相同时是会自动合并的,同理 _flex.Columns[j].AllowMerging = true; 也会自动处理 j 列自动合并。

    C1FlexGrid 的 AllowMerging 属性是个枚举值,可选 AllAllHeadersCellsColumnHeadersNone(默认)、RowHeaders,需要注意的是,行列的 AllowMerging 属性是必须结合C1FlexGrid 的 AllowMerging 属性来使用的,比如你要设置行头和列头区域的自动合并,则需要设置 _flex.AllowMerging = AllHeaders; ,其他区域同理。

    下面举一个简单的例子,看一下效果:

    flex.AllowMerging = AllowMerging.Cell
    flex[0, 0] = 1
    flex[0, 1] = 1
    flex.Rows[0].AllowMerging = true
    flex[1, 1] = 3
    flex[2, 1] = 3
    flex.Columns[1].AllowMerging = true
    
    flex.AllowMerging = AllowMerging.ColumnHeader
    flex.ColumnHeaders[0, 1] = "A"
    flex.ColumnHeaders[0, 2] = "A"
    flex.ColumnHeaders.Rows[0].AllowMerging = true
    
    flex.AllowMerging = AllowMerging.RowHeader
    flex.RowHeaders[0, 0] = "1"
    flex.RowHeaders[1, 0] = "1"
    flex.RowHeaders[2, 0] = "1"
    flex.RowHeaders.Columns[0].AllowMerging = true
     
    flex.AllowMerging = AllowMerging.All;
    // 为了看到效果
    View Code

    效果如下图所示:

    image

    二  正文

    现在要做一套可以灵活设置 C1FlexGrid 的合并和拆分机制,需要用到 C1FlexGrid 的 MergeManager 属性,其专门负责管理合并单元格;MergeManger 是实现了接口 IMergeManager,里面有一个方法是

    public CellRange GetMergedRange(C1FlexGrid grid, CellType cellType, CellRange range)

    该方法会在每次重绘单元格时自动调用,以获取合并单元格区域,从而进行处理;所以我们自己定义一个 MergeManager 来管理合并单元格。

    using System.Collections.Generic
    using C1.Silverlight.FlexGrid
    
    namespace SLFlexGridCellMerge
    {
        public class MergeManagerExt : IMergeManager
        {
            #region 私有变量
    
            private List<CellRange> _mergedRanges;// 合并区域集合
            
            #endregio
    
            #region 公开属性
    
            /// <summary>
            /// 合并单元格集合
            /// </summary>
            public List<CellRange> MergedRange
            {
                get
                {
                    return _mergedRange
                }
                set
                {
                    _mergedRanges = value
                }
            }
            
            #endregio
    
            #region 构造函数
    
            /// <summary>
            /// 构造函数
            /// </summary>
            public MergeManagerExt()
            {
                _mergedRanges = new List<CellRange>()
            }
            
            #endregio
    
            #region 公开方法
    
            /// <summary>
            /// <para>IMergeManager接口方法</para>
            /// <para>获取range所在合并区域</para>
            /// </summary>
            public CellRange GetMergedRange(C1FlexGrid grid, CellType cellType, CellRange range)
            {
                CellRange cellRange = range
                if (cellType == CellType.Cell)
                {
                    foreach (CellRange mergedRange in _mergedRanges)
                    {
                        if (mergedRange.Contains(range))
                        {
                            cellRange = mergedRange
                            break
                        }
                    }
                }
    
                return cellRange.Normalize()
            }
    
            /// <summary>
            /// 获取某个选定区域所在的合并单元格区域
            /// </summary>
            /// <param name="selection">已选定区域</param>
            /// <returns>选定区域所在的合并单元格区域</returns>
            public CellRange GetMergedRange(CellRange selection)
            {
                CellRange cellRange = selectio
                foreach (CellRange range in _mergedRanges)
                {
                    if (range.Intersects(cellRange))
                    {
                        cellRange = cellRange.Union(range)
                    }
                }
    
                return cellRange.Normalize()
            }
    
            /// <summary>
            /// 判断选区内是否有合并单元格
            /// </summary>
            /// <param name="selection">选区</param>
            /// <returns>选区内是否有合并单元格</returns>
            public bool HasMergedRange(CellRange selection)
            {
                bool flag = false
                CellRange cellRange = GetMergedRange(selection)
                foreach (CellRange item in _mergedRanges)
                {
                    if (cellRange.Contains(item))
                    {
                        flag = true
                        break
                    }
                }
    
                return flag
            }
    
            /// <summary>
            /// 增加合并单元格范围
            /// </summary>
            /// <param name="cellRange">新增要合并的单元格范围</param>
            public void AddMergedRange(CellRange selection)
            {
                CellRange cellRange = GetMergedRange(selection)
                if (!cellRange.IsSingleCell)
                {
                    bool isIn = false;// 是否已经包含在合并单元格中
                    for (int i = 0; i < _mergedRanges.Count; i++)
                    {
                        // 新增的合并区域包含了已经合并的单元格
                        if (cellRange.Contains(_mergedRanges[i]))
                        {
                            _mergedRanges.RemoveAt(i)
                            i--
                        }
                        else if (_mergedRanges[i].Contains(cellRange))
                        {
                            isIn = true
                        }
                    }
                    if (!isIn)
                    {
                        _mergedRanges.Add(cellRange.Normalize())
                    }
                }
            }
    
            /// <summary>
            /// 拆分单元格
            /// </summary>
            /// <param name="mergedRange">需要拆分的单元格范围</param>
            public void RemoveMergedRange(CellRange selection)
            {
                CellRange cellRange = GetMergedRange(selection)
                for (int i = 0; i < _mergedRanges.Count; i++)
                {
                    if (cellRange.Intersects(_mergedRanges[i]))
                    {
                        _mergedRanges.RemoveAt(i)
                        i--
                    }
                }
            }
        }
    }
    
    View Code

    在自定义的 MergeManagerExt 中,利用一个 List 来管理合并区域,然后在接口 IMergeManager 的方法 GetMergedRange 中,根据重绘时扫描到的 range (参数),从 List 中查找包含该 range 的合并区域并返回。

    然后就可以将 C1FlexGrid 的 Selection 通过方法 AddMergeRange 和 RemoveMergeRange 添加或移除到合并区域集合(List),进行管理,C1FlexGrid 则在每次重绘单元格时通过接口方法 GetMergedRange 获取合并区域集合进行合并处理,这样就可以达到灵活设置单元格的合并和拆分了。

    三  扩展

    合并区域集合是一个 List<CellRange> 类型,其中 CellRange 简单的记录了 LeftColumn, TopRow, RightColumn, BottomRow 四个整型值,以标记出范围的左上角和右下角坐标。这样会导致一个问题,就是如果 C1FlexGrid 的行列数目已经固定下来了,不再增删,自然可用;但是如果 C1FlexGrid 的行列也是动态增删,此时合并集合中的 CellRange 所标记的范围坐标并没有即时更新,导致在行列增删后,合并范围移位或者超出 C1FlexGrid 范围。

    解决方法是在进行行列增删时,同步更新合并区域集合中的 CellRange。

    在插入列时:

    • 如果插入的列在合并范围左侧(包括合并范围左列),则将合并范围整体右移1列;
    • 如果插入的列在合并范围之间(不包括合并范围左列,包括合并范围右列),则将合并范围扩张1列,其中左列不动,右列+1;
    • 如果插入的列在合并范围右侧以外,则不影响该合并范围;

    在插入行时同上逻辑,楼主就不赘述了。

    删除时就比较复杂了,楼主逻辑能力欠差,就画了一张图表说明:

    image

    白色、绿色蓝色均是表示选中要删除的行(按列算,每一列算作一种情况),黄色则表格某个合并范围;

    其中红色标注的数据表示该情况会把整个合并范围移除;

    上面这是删除行时的情况列举,删除列的逻辑同理就不说了。在自定义的 MergeManagerExt 中增加几个更新合并范围的方法:

    /// <summary>
    /// 插入列时,与其相关的合并单元格范围更新
    /// </summary>
    /// <param name="colIndex">插入列的索引位置</param>
    public void InsertColumnUpdate(int colIndex)
    {
        for (int i = 0; i < _mergedRanges.Count; i++)
        {
            if (_mergedRanges[i].LeftColumn >= colIndex)
            {
                int top = _mergedRanges[i].TopRow
                int left = _mergedRanges[i].LeftColumn + 1
                int bottom = _mergedRanges[i].BottomRow
                int right = _mergedRanges[i].RightColumn + 1
                _mergedRanges[i] = new CellRange(top, left, bottom, right)
            }
            else if (_mergedRanges[i].LeftColumn < colIndex && colIndex <= _mergedRanges[i].RightColumn)
            {
                int top = _mergedRanges[i].TopRow
                int left = _mergedRanges[i].LeftColum
                int bottom = _mergedRanges[i].BottomRow
                int right = _mergedRanges[i].RightColumn + 1
                _mergedRanges[i] = new CellRange(top, left, bottom, right)
            }
        }
    }
    
    /// <summary>
    /// 插入行时,与其相关的合并单元格范围更新
    /// </summary>
    /// <param name="rowIndex">插入行的索引位置</param>
    public void InsertRowUpdate(int rowIndex)
    {
        for (int i = 0; i < _mergedRanges.Count; i++)
        {
            if (_mergedRanges[i].TopRow >= rowIndex)
            {
                int top = _mergedRanges[i].TopRow + 1
                int left = _mergedRanges[i].LeftColum
                int bottom = _mergedRanges[i].BottomRow + 1
                int right = _mergedRanges[i].RightColum
                _mergedRanges[i] = new CellRange(top, left, bottom, right)
            }
            else if (_mergedRanges[i].TopRow < rowIndex && rowIndex <= _mergedRanges[i].BottomRow)
            {
                int top = _mergedRanges[i].TopRow
                int left = _mergedRanges[i].LeftColum
                int bottom = _mergedRanges[i].BottomRow + 1
                int right = _mergedRanges[i].RightColum
                _mergedRanges[i] = new CellRange(top, left, bottom, right)
            }
        }
    }
    
    /// <summary>
    /// 删除选定区域的行时,更新MergeManager内相对应的合并单元区域
    /// </summary>
    /// <param name="selection">当前选定区域所在的行区域</param>
    public void DeleteRowsUpdate(CellRange selectedRows)
    {
        for (int i = 0; i < _mergedRanges.Count; i++)
        {
            if (_mergedRanges[i].BottomRow >= selectedRows.TopRow)
            {
                CellRange intersection = _mergedRanges[i].Intersection(selectedRows)
                int topRow = _mergedRanges[i].TopRow
                int bottomRow = _mergedRanges[i].BottomRow
                if (_mergedRanges[i].TopRow <= selectedRows.TopRow)
                {
                    topRow = _mergedRanges[i].TopRow
                    bottomRow = _mergedRanges[i].BottomRow - intersection.RowSpa
                }
                else
                {
                    if (intersection.IsValid)
                    {
                        topRow = selectedRows.TopRow
                    }
                    else
                    {
                        topRow = _mergedRanges[i].TopRow - selectedRows.RowSpa
                    }
                    bottomRow = _mergedRanges[i].BottomRow - selectedRows.RowSpa
                }
                if (topRow > bottomRow ||
                    ((topRow == bottomRow) && _mergedRanges[i].ColumnSpan == 1))
                {
                    _mergedRanges.RemoveAt(i)
                    i--
                    continue
                }
                _mergedRanges[i] = new CellRange(topRow, _mergedRanges[i].LeftColumn, bottomRow, _mergedRanges[i].RightColumn)
            }
        }
    }
    
    /// <summary>
    /// 删除选定区域的列时,更新MergeManager内相对应的合并单元区域
    /// </summary>
    /// <param name="selection">当前选中的区域</param>
    public void DeleteColumnsUpdate(CellRange selectedColumns)
    {
        for (int i = 0; i < _mergedRanges.Count; i++)
        {
            if (_mergedRanges[i].RightColumn >= selectedColumns.LeftColumn)
            {
                CellRange intersection = _mergedRanges[i].Intersection(selectedColumns)
                int leftColumn = _mergedRanges[i].LeftColum
                int rightColumn = _mergedRanges[i].RightColum
                if (_mergedRanges[i].LeftColumn <= selectedColumns.LeftColumn)
                {
                    leftColumn = _mergedRanges[i].LeftColum
                    rightColumn = _mergedRanges[i].RightColumn - intersection.ColumnSpa
                }
                else
                {
                    if (intersection.IsValid)
                    {
                        leftColumn = selectedColumns.LeftColum
                    }
                    else
                    {
                        leftColumn = _mergedRanges[i].LeftColumn - selectedColumns.ColumnSpa
                    }
                    rightColumn = _mergedRanges[i].RightColumn - selectedColumns.ColumnSpa
                }
    
                if (leftColumn > rightColumn ||
                    ((leftColumn == rightColumn) && _mergedRanges[i].RowSpan == 1))
                {
                    _mergedRanges.RemoveAt(i)
                    i--
                    continue
                }
                _mergedRanges[i] = new CellRange(_mergedRanges[i].TopRow, leftColumn, _mergedRanges[i].BottomRow, rightColumn)
            }
        }
    }
    
    
    View Code

    四  展示

    楼主自然以此做了个 Demo,看看效果吧热烈的笑脸

    image

  • 相关阅读:
    MYSQL存储引擎
    微信公众号自定义菜单
    TCP 三次握手与四次挥手
    微信扫码关注公众号并登录网站
    redis scan命令使用
    [转]Maven多模块结构下版本管理的正确姿势-revision
    线程间的协作wait,notify,sleep,yield,join
    GIT 撤销操作
    Kafka学习理解-listeners配置
    Kafka 简介梳理
  • 原文地址:https://www.cnblogs.com/memento/p/4425544.html
Copyright © 2020-2023  润新知