zoukankan      html  css  js  c++  java
  • WinForm 树形列表(多级) 可展开,可折叠

    Datagridview 实现树形列表的效果

    (2020年6月9日 :换了个gif,之前的图感觉不太好,没表现出什么)

    菜单文字都做了改动,防止泄露公司的密码,毕竟签了协议的

    代码中有两个字典类型

            // 记录菜单节点的层级
            Dictionary<string, int> _dictIsPMenu;
            // 是否展开
            Dictionary<string, bool> _dictPMenuExpand;

    2020年6月11日更新

    递归做了优化,之前的递归层级的保存有问题,最开始的if是一个层级的判断,如果想要递归多少级可以自己修改

            private void CreateTree(string pMenuId, int layer)
            {
                if (layer > 3) 
                    return;
                int thisLayer = layer;
                List<M_Menu> childMenuList = allMenuList.Where(a => a.MM_PMenID == pMenuId).ToList();
                for (int i = 0; i < childMenuList.Count; i++)
                {
                    menuList.Add(childMenuList[i]);
                    _dictPMenuExpand.Add(childMenuList[i].MM_MenID, true);
                    _dictIsPMenu.Add(childMenuList[i].MM_MenID, thisLayer);
                    layer++;
                    CreateTree(childMenuList[i].MM_MenID, layer);
                }
            }

    2020年6月3日更新

    使用了递归,可以做到无限级,但是有个问题,就是列表展示的不太好,

    数据获取:

    其中部分代码变成下面的样子了

                // 循环顶级节点
                for (int i = 0; i < topMenuList.Count; i++)
                {
    
                    menuList.Add(topMenuList[i]);
                    _dictIsPMenu.Add(topMenuList[i].MM_MenID, 1);
                    _dictPMenuExpand.Add(topMenuList[i].MM_MenID, true);
                    CreateTree(topMenuList[i].MM_MenID, 2);
                }

    递归方法:这个递归有个问题就是层级有点问题,但是除了显示的层级不明确以外,其他都还好

            /// <summary>
            /// 创建树列表递归
            /// </summary>
            /// <param name="pMenuId">父菜单</param>
            /// <param name="layer">层级</param>
            private void CreateTree(string pMenuId, int layer)
            {
                List<M_Menu> childMenuList = allMenuList.Where(a => a.MM_PMenID == pMenuId).ToList();
                for (int i = 0; i < childMenuList.Count; i++)
                {
                    menuList.Add(childMenuList[i]);
                    _dictPMenuExpand.Add(childMenuList[i].MM_MenID, true);
                    _dictIsPMenu.Add(childMenuList[i].MM_MenID, layer);
                    CreateTree(childMenuList[i].MM_MenID, layer++);
                }
            }

    单元格绘制代码做了一点小改动

            /// <summary>
            /// 单元格绘制
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void dgvMenuList_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
            {
    
                if (e.RowIndex >= 0 && dgvMenuList.Columns[e.ColumnIndex].DataPropertyName == "MM_MenName")
                {
    
                    string menuId = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_MenID"].Value.ToString();
                    string menuName = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_MenName"].Value.ToString();
                    string pMenuId = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_PMenID"].Value.ToString();
                    Image img;
                    Rectangle newRect;
                    if (pMenuId == GuidEmpty)
                    {
                        img = _dictPMenuExpand[menuId] ? Properties.Resources.tree_icon_two : Properties.Resources.tree_icon_one;
                        newRect = new Rectangle(
                            e.CellBounds.X + 3,
                            e.CellBounds.Y + e.CellBounds.Height / 2 - img.Height / 2,
                            img.Width,
                            img.Height);
                    }
                    else
                    {
                        img = Properties.Resources.tree_icon_three;
                        // 如果有子集
                        var orgList = menuList.Where(s => s.MM_PMenID.Equals(menuId)).ToList();
                        if (orgList.Count > 0)
                        {
                            img = _dictPMenuExpand[menuId] ? Properties.Resources.tree_icon_two : Properties.Resources.tree_icon_one;
                        }
                        newRect = new Rectangle(
                            e.CellBounds.X + 3 + 10,
                            e.CellBounds.Y + e.CellBounds.Height / 2 - img.Height / 2,
                            img.Width,
                            img.Height);
                        //判断当前父节点是不是二级父节点
                        if (_dictIsPMenu[pMenuId] >= 2)
                        {
                            newRect.X += 10 * (_dictIsPMenu[pMenuId] - 1);
                        }
                    }
    
    
                    using (Brush gridBrush = new SolidBrush(this.dgvMenuList.GridColor),
                        backColorBrush = new SolidBrush(e.CellStyle.BackColor))
                    {
                        using (Pen gridLinePen = new Pen(gridBrush, 2))
                        {
                            // 擦除单元格
                            e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
                            //绘制背景色:如果选中那就用选中的蓝色背景色,否则用默认白色背景色
                            if (dgvMenuList.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected)
                            {
                                e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(172, 204, 253)), e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width - 1, e.CellBounds.Height - 1);
                            }
                            else
                            {
                                e.Graphics.FillRectangle(new SolidBrush(dgvMenuList.DefaultCellStyle.BackColor), e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width - 1, e.CellBounds.Height - 1);
                            }
                            //划线
                            Point p1 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top);
                            Point p2 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top + e.CellBounds.Height);
                            Point p3 = new Point(e.CellBounds.Left, e.CellBounds.Top + e.CellBounds.Height);
                            Point[] ps = new Point[] { p1, p2, p3 };
                            e.Graphics.DrawLines(gridLinePen, ps);
                            //画图标
                            e.Graphics.DrawImage(img, newRect);
                            //画字符串
                            e.Graphics.DrawString(menuName.ToString(), this.Font, Brushes.Black,
                                newRect.X + 3 * 2 + img.Width, e.CellBounds.Top + Font.GetHeight(), StringFormat.GenericDefault);
                            e.Handled = true;
                        }
                    }
                }
            }

    单元格点击也做了改动,可以一次性展开所有子节点

            /// <summary>
            /// 单元格点击
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void dgvMenuList_CellClick(object sender, DataGridViewCellEventArgs e)
            {
                int rowIndex = e.RowIndex;
                int colIndex = e.ColumnIndex;
                // 点中序号和标题列就返回
                if (colIndex == 0 || rowIndex < 0)
                {
                    return;
                }
                string menuId = dgvMenuList.Rows[e.RowIndex].Cells["MM_MenID"].Value.ToString();
                string pMenuId = dgvMenuList.Rows[e.RowIndex].Cells["MM_PMenID"].Value.ToString();
                // 判断当前菜单ID是否是父级菜单
                if (pMenuId == GuidEmpty || (menuList.Where(s => s.MM_PMenID.Equals(menuId)).Count() > 0))
                {
    
                    string menuName = dgvMenuList.Rows[e.RowIndex].Cells["MM_MenName"].Value.ToString();
                    SetBtnShowHideState(pMenuId);
                    EnergyBtnSetShow(true);
                    gpObjChecks.Controls.Clear();
                    bool state = !_dictPMenuExpand[menuId];
                    _dictPMenuExpand[menuId] = state;
                    ExpandMenu(menuId, state);
                }
                else
                {
                    SetBtnShowHideState(pMenuId);
                    AddCheckBoxs(menuId);
                }
            }

    折叠收起递归

            /// <summary>
            /// 展开折叠递归
            /// </summary>
            /// <param name="pid">父菜单id</param>
            /// <param name="state">折叠还是收起</param>
            private void ExpandMenu(string pid, bool state)
            {
                List<M_Menu> childList = menuList.Where(s => s.MM_PMenID.Equals(pid)).ToList();
                //筛选传入的子集合
                for (int i = 0; i < childList.Count; i++)
                {
                    for (int j = 0; j < dgvMenuList.RowCount; j++)
                    {
                        string thisMenuId = dgvMenuList.Rows[j].Cells["MM_MenID"].Value.ToString();
                        if (thisMenuId == childList[i].MM_MenID)
                        {
                            dgvMenuList.Rows[j].Visible = state;
                        }
                    }
                    ExpandMenu(childList[i].MM_MenID, state);
                }
    
            }

    2020年5月30日

    首先需要绑定一个对应数据的泛型集合,其他的数据暂时没试过

                Dictionary<string, int>  _dictIsPMenu = new Dictionary<string, int>();
                Dictionary<string, bool> _dictPMenuExpand = new Dictionary<string, bool>();
    
                List<M_Menu> temp = 某个数据接口
                List<M_Menu> topMenuList = temp.Where(a => a.MM_PMenID == GuidEmpty).ToList();
                List<M_Menu> menuList = new List<M_Menu>(topMenuList.ToArray());//深拷贝
                List<M_Menu> secondMenuList;
                List<M_Menu> thirdMenuList;
                int index = 0;
                // 循环顶级节点
                for (int i = 0; i < topMenuList.Count; i++)
                {
                    // 查询顶级节点下的子节点
                    secondMenuList = temp.Where(a => a.MM_PMenID == topMenuList[i].MM_MenID).ToList();
                    // 向数据字典添加数据
                    _dictIsPMenu.Add(topMenuList[i].MM_MenID, 1);
              // true 为默认展开 _dictPMenuExpand.Add(topMenuList[i].MM_MenID,
    true); // 循环对应子节点 for (int j = 0; j < secondMenuList.Count; j++) { menuList.Insert(++index, secondMenuList[j]); // 二级子节点 thirdMenuList = temp.Where(a => a.MM_PMenID == secondMenuList[j].MM_MenID).ToList(); if (thirdMenuList.Count > 0) { _dictIsPMenu.Add(secondMenuList[j].MM_MenID, 2); _dictPMenuExpand.Add(secondMenuList[j].MM_MenID, true); for (int k = 0; k < thirdMenuList.Count; k++) { menuList.Insert(++index, thirdMenuList[k]); } } } index++; } // 此数据只会查出二级子菜单的数据 dgvMenuList.DataSource = menuList;

    然后在datagridview的CellPoint  中写入画图的代码

    // 判断是否是需要画图的列
    if (e.RowIndex >= 0 && dgvMenuList.Columns[e.ColumnIndex].DataPropertyName == "MM_MenName")
                {
    
                    string menuId = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_MenID"].Value.ToString();
                    string menuName = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_MenName"].Value.ToString();
                    string pMenuId = this.dgvMenuList.Rows[e.RowIndex].Cells["MM_PMenID"].Value.ToString();
                    Image img;
                    Rectangle newRect;
                    if (_dictIsPMenu.ContainsKey(menuId))
                    {
                        img = _dictPMenuExpand[menuId] ? Properties.Resources.tree_icon_two : Properties.Resources.tree_icon_one;
                        newRect = new Rectangle(
                            e.CellBounds.X + 3,
                            e.CellBounds.Y + e.CellBounds.Height / 2 - img.Height / 2,
                            img.Width,
                            img.Height);
                        //判断当前节点是不是二级父节点
                        if (_dictIsPMenu[menuId] == 2)
                        {
                            newRect.X += 10;
                        }
                    }
                    else
                    {
                        img = Properties.Resources.tree_icon_three;
                        newRect = new Rectangle(
                            e.CellBounds.X + 3 + 10,
                            e.CellBounds.Y + e.CellBounds.Height / 2 - img.Height / 2,
                            img.Width,
                            img.Height);
                        //判断当前父节点是不是二级父节点
                        if (_dictIsPMenu[pMenuId] == 2)
                        {
                            newRect.X += 10;
                        }
                    }
    
    
                    using (Brush gridBrush = new SolidBrush(this.dgvMenuList.GridColor),
                        backColorBrush = new SolidBrush(e.CellStyle.BackColor))
                    {
                        using (Pen gridLinePen = new Pen(gridBrush, 2))
                        {
                            // 擦除单元格
                            e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
                            //绘制背景色:如果选中那就用设置的背景色,否则用默认白色背景色
                            if (dgvMenuList.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected)
                            {
                                e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(172, 204, 253)), e.CellBounds.X , e.CellBounds.Y , e.CellBounds.Width - 1, e.CellBounds.Height - 1);
                            }
                            else
                            {
                                e.Graphics.FillRectangle(new SolidBrush(dgvMenuList.DefaultCellStyle.BackColor), e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width - 1, e.CellBounds.Height - 1);
                            }
                            //划线
                            Point p1 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top);
                            Point p2 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top + e.CellBounds.Height);
                            Point p3 = new Point(e.CellBounds.Left, e.CellBounds.Top + e.CellBounds.Height);
                            Point[] ps = new Point[] { p1, p2, p3 };
                            e.Graphics.DrawLines(gridLinePen, ps);
                            //画图标
                            e.Graphics.DrawImage(img, newRect);
                            //画字符串
                            e.Graphics.DrawString(menuName.ToString(), this.Font, Brushes.Black,
                                newRect.X + 3 * 2 + img.Width, e.CellBounds.Top + Font.GetHeight(), StringFormat.GenericDefault);
                            e.Handled = true;
                        }
                    }
                }

    然后实现点击展开折叠,通过datagridview 的CellClick事件,如果这个事件觉得不好也可用换一个事件,只要能获取到对应行列就行

    private void dgvMenuList_CellClick(object sender, DataGridViewCellEventArgs e)
            {
                int rowIndex = e.RowIndex;
                int colIndex = e.ColumnIndex;
                // 点中序号和标题列就返回
                if (colIndex == 0 || rowIndex < 0)
                {
                    return;
                }
                string menuId = dgvMenuList.Rows[e.RowIndex].Cells["MM_MenID"].Value.ToString();
                // 判断当前菜单ID是否是父级菜单
                if (_dictIsPMenu.ContainsKey(menuId))
                {
                    string menuName = dgvMenuList.Rows[e.RowIndex].Cells["MM_MenName"].Value.ToString();
    
                    gpObjChecks.Controls.Clear();
                    for (int i = e.RowIndex + 1; i < dgvMenuList.RowCount; i++)
                    {
                        string pMenuId = dgvMenuList.Rows[i].Cells["MM_PMenID"].Value.ToString();
                        string tempMenuId = dgvMenuList.Rows[i].Cells["MM_MenID"].Value.ToString();
                        bool state = !_dictPMenuExpand[menuId];
                        // 顶级父级
                        if (_dictIsPMenu[menuId] == 1)
                        {
                            //判断是否到下一个顶级父级菜单了
                            if (pMenuId == GuidEmpty)
                            {
                                _dictPMenuExpand[menuId] = state;
    
                                break;
                            }
                            dgvMenuList.Rows[i].Visible = state;
                            _dictPMenuExpand[tempMenuId] = state;
                            // 当前父菜单不是下一个顶级父菜单,但是是下一级父菜单
                            if (pMenuId != menuId)
                            {
                                dgvMenuList.Rows[i].Visible = _dictPMenuExpand[pMenuId];
                            }
                        }
                        // 次级父级
                        else
                        {
                            //判断是否到下一个次级父级菜单了
                            if (pMenuId != menuId)
                            {
                                _dictPMenuExpand[menuId] = state;
                                break;
                            }
                            else
                            {
                                dgvMenuList.Rows[i].Visible = state;
                            }
                        }
                        // 最后一行的特殊处理
                        if (i == dgvMenuList.RowCount - 1)
                        {
                            _dictPMenuExpand[menuId] = state;
                            dgvMenuList.Rows[i].Visible = state;
                        }
                    }
                }
                else
                {
                    string pMenuId = dgvMenuList.Rows[e.RowIndex].Cells["MM_PMenID"].Value.ToString();
                    M_Menu menu = _menuBLL.GetMenu(pMenuId);
    
                }
            }

    这篇就这些

  • 相关阅读:
    android SQLite使用
    蓝牙从搜索到成功配对的全过程
    vscode 开发.net core 从安装到部署 教程详解
    ServiceStack 简单服务搭建
    MongoDB 安装配置
    request.url 端口 错误
    Python 之 hello world
    .NET DateTime 源码学习
    Parallel.For 平行算法 使用
    Thread.Join 和 Task.Wait 方法
  • 原文地址:https://www.cnblogs.com/wu-xin/p/12992519.html
Copyright © 2011-2022 走看看