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

            }
        }

這篇就這些

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM