• 热门专题

Silverlight C1FlexGrid行列增删&单元格合并拆分

作者:Memento  发布日期:2015-04-14 20:54:39
Tag标签:行列  单元  
  • 上一篇中实现了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;// 为了看到效果
    

    效果如下图所示:

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

    在自定义的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)
            }
        }
    }
    
    

    四  展示

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

    image

    五  资源下载

    Demo工程:http://www.it165.net/uploadfile/files/2015/0414/SLFlexGridCellMerge.zip

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规