You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新手求教:如何从带分类与子分类的SQL循环生成PopupMenu并添加指定条目

基于层级SQL数据构建PopupMenu并添加固定子项的实现示例

需求说明

从包含分类、子分类的SQL层级数据(带Level_Depth字段标记层级)中循环生成PopupMenu,并为所有Level_Depth=3的菜单节点追加两个固定条目。


第一步:准备SQL表与测试数据

先创建存储菜单层级的表,并插入测试数据:

-- 创建菜单分类表
CREATE TABLE MenuCategories (
    ID INT PRIMARY KEY,
    ParentID INT NULL, -- 父分类ID,根节点为NULL或0
    Name NVARCHAR(100) NOT NULL,
    Level_Depth INT NOT NULL -- 层级深度,根节点为1
);

-- 插入测试数据
INSERT INTO MenuCategories VALUES
(1, NULL, '主分类1', 1),
(2, 1, '子分类1-1', 2),
(3, 2, '孙分类1-1-1', 3),
(4, 1, '子分类1-2', 2),
(5, 4, '孙分类1-2-1', 3),
(6, NULL, '主分类2', 1),
(7, 6, '子分类2-1', 2),
(8, 7, '孙分类2-1-1', 3);

第二步:桌面端(C# WinForms)实现示例

以下代码通过WinForms的ContextMenuStrip实现PopupMenu,从SQL读取数据并构建层级菜单,最后为三级节点添加固定条目:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;

namespace PopupMenuDemo
{
    public partial class MainForm : Form
    {
        // 替换为你的数据库连接字符串
        private const string ConnectionString = "Data Source=YOUR_SERVER;Initial Catalog=YOUR_DB;Integrated Security=True";

        public MainForm()
        {
            InitializeComponent();
            LoadPopupMenu();
        }

        private void LoadPopupMenu()
        {
            // 1. 从SQL获取菜单数据
            DataTable menuTable = GetMenuData();

            // 2. 存储所有菜单项,方便快速查找父节点
            Dictionary<int, ToolStripMenuItem> menuItemDict = new Dictionary<int, ToolStripMenuItem>();

            // 先创建所有菜单项
            foreach (DataRow row in menuTable.Rows)
            {
                int id = Convert.ToInt32(row["ID"]);
                string menuName = row["Name"].ToString();

                ToolStripMenuItem item = new ToolStripMenuItem(menuName);
                item.Tag = id; // 存储ID用于后续逻辑
                menuItemDict.Add(id, item);
            }

            // 3. 构建菜单父子层级
            foreach (DataRow row in menuTable.Rows)
            {
                int id = Convert.ToInt32(row["ID"]);
                int? parentId = row["ParentID"] != DBNull.Value ? (int?)Convert.ToInt32(row["ParentID"]) : null;

                if (parentId.HasValue && menuItemDict.ContainsKey(parentId.Value))
                {
                    // 子节点添加到父节点的下拉列表
                    menuItemDict[parentId.Value].DropDownItems.Add(menuItemDict[id]);
                }
                else
                {
                    // 根节点直接添加到主PopupMenu
                    contextMenuStrip1.Items.Add(menuItemDict[id]);
                }
            }

            // 4. 为所有Level_Depth=3的节点添加固定条目
            foreach (DataRow row in menuTable.Rows)
            {
                int level = Convert.ToInt32(row["Level_Depth"]);
                if (level == 3)
                {
                    int id = Convert.ToInt32(row["ID"]);
                    if (menuItemDict.ContainsKey(id))
                    {
                        // 添加分隔线
                        menuItemDict[id].DropDownItems.Add(new ToolStripSeparator());
                        // 添加固定条目并绑定点击事件
                        menuItemDict[id].DropDownItems.Add("固定条目1", null, FixedItem_Click);
                        menuItemDict[id].DropDownItems.Add("固定条目2", null, FixedItem_Click);
                    }
                }
            }
        }

        // 从SQL读取菜单数据
        private DataTable GetMenuData()
        {
            DataTable dt = new DataTable();
            using (SqlConnection conn = new SqlConnection(ConnectionString))
            {
                string sql = "SELECT ID, ParentID, Name, Level_Depth FROM MenuCategories ORDER BY Level_Depth, ID";
                SqlCommand cmd = new SqlCommand(sql, conn);
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(dt);
            }
            return dt;
        }

        // 固定条目的点击事件
        private void FixedItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem clickedItem = sender as ToolStripMenuItem;
            MessageBox.Show($"你点击了:{clickedItem.Text}");
        }
    }
}

第三步:Web端(Bootstrap Dropdown)实现示例

如果是Web场景,用Bootstrap的下拉菜单组件实现类似功能:

<!-- HTML容器 -->
<div class="dropdown">
  <button class="btn btn-secondary dropdown-toggle" type="button" id="mainMenuBtn" data-bs-toggle="dropdown" aria-expanded="false">
    弹出菜单
  </button>
  <ul class="dropdown-menu" aria-labelledby="mainMenuBtn" id="menuContainer">
  </ul>
</div>

<script>
// 模拟从后端接口获取的SQL菜单数据(实际项目用AJAX请求)
const menuData = [
  { ID: 1, ParentID: null, Name: '主分类1', Level_Depth: 1 },
  { ID: 2, ParentID: 1, Name: '子分类1-1', Level_Depth: 2 },
  { ID: 3, ParentID: 2, Name: '孙分类1-1-1', Level_Depth: 3 },
  { ID: 4, ParentID: 1, Name: '子分类1-2', Level_Depth: 2 },
  { ID: 5, ParentID: 4, Name: '孙分类1-2-1', Level_Depth: 3 },
  { ID: 6, ParentID: null, Name: '主分类2', Level_Depth: 1 },
  { ID: 7, ParentID: 6, Name: '子分类2-1', Level_Depth: 2 },
  { ID: 8, ParentID: 7, Name: '孙分类2-1-1', Level_Depth: 3 }
];

function buildPopupMenu() {
  const menuContainer = document.getElementById('menuContainer');
  const menuItemMap = {};

  // 1. 创建所有菜单项
  menuData.forEach(item => {
    const li = document.createElement('li');
    const link = document.createElement('a');
    link.className = 'dropdown-item';
    link.href = '#';
    link.textContent = item.Name;

    if (item.Level_Depth !== 3) {
      // 非三级节点作为下拉菜单容器
      link.classList.add('dropdown-toggle');
      link.setAttribute('data-bs-toggle', 'dropdown');
      link.setAttribute('aria-expanded', 'false');
      const subMenu = document.createElement('ul');
      subMenu.className = 'dropdown-menu';
      li.appendChild(link);
      li.appendChild(subMenu);
    } else {
      // 三级节点直接作为可点击项
      li.appendChild(link);
    }
    menuItemMap[item.ID] = li;
  });

  // 2. 构建父子层级关系
  menuData.forEach(item => {
    if (item.ParentID !== null) {
      const parentLi = menuItemMap[item.ParentID];
      const subMenu = parentLi.querySelector('.dropdown-menu');
      subMenu.appendChild(menuItemMap[item.ID]);
    } else {
      menuContainer.appendChild(menuItemMap[item.ID]);
    }
  });

  // 3. 为三级节点添加固定条目
  menuData.forEach(item => {
    if (item.Level_Depth === 3) {
      const li = menuItemMap[item.ID];
      // 添加分隔线
      const divider = document.createElement('li');
      divider.className = 'dropdown-divider';
      li.appendChild(divider);
      // 添加固定条目1
      const fixedItem1 = createFixedMenuItem('固定条目1');
      li.appendChild(fixedItem1);
      // 添加固定条目2
      const fixedItem2 = createFixedMenuItem('固定条目2');
      li.appendChild(fixedItem2);
    }
  });
}

// 创建固定菜单项的工具函数
function createFixedMenuItem(text) {
  const link = document.createElement('a');
  link.className = 'dropdown-item';
  link.href = '#';
  link.textContent = text;
  link.addEventListener('click', () => alert(`点击了:${text}`));
  const li = document.createElement('li');
  li.appendChild(link);
  return li;
}

// 页面加载完成后构建菜单
document.addEventListener('DOMContentLoaded', buildPopupMenu);
</script>

内容的提问来源于stack exchange,提问作者Ricky Rock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:50:11