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

ASP.NET(VB.NET)菜单权限配置页面开发求助:ListBox联动+暂存

主菜单与子菜单权限配置页面逻辑完善(ASP.NET+VB.NET)

需求概述

  • 主菜单权限切换(锁定/开启)时,下属所有子菜单权限同步变更
  • 权限状态通过两组ListBox展示:
    • 主菜单:Dikunci(锁定列表)、Dibuka(开启列表)
    • 子菜单:Dikunci1(锁定列表)、Dibuka1(开启列表)
  • 手动调整权限后变更暂存,点击Simpan按钮才持久化生效
  • 点击Batal按钮放弃所有未保存的权限调整

现有ASPX页面代码

<div class="form-group" id="Modul" runat="server" visible="false">
    <div class="form-group" id="snippet1Content" runat="server" visible="true">
         <label class="col-md-3 control-label"></label>
         <div class="col-md-4">
             <label>Dikunci</label>
             <asp:ListBox ID="Dikunci" runat="server" Width="300px" Height="170px"
                          AutoPostBack="True"  SelectionMode="Multiple" onchange="updateSubMenuList()"></asp:ListBox>
             <div>
                 <label>Dikunci</label>
                 <asp:ListBox ID="Dikunci1" runat="server" Width="300px" Height="170px" 
                              AutoPostBack="True" SelectionMode="Multiple" onchange="updateSubMenuList()"></asp:ListBox>
             </div>
         </div>
         <div class="col-md-4">
             <label>Dibuka</label>
             <asp:ListBox ID="Dibuka" runat="server" Width="300px" Height="170px" 
                          AutoPostBack="True"  SelectionMode="Multiple" onchange="updateSubMenuList()"></asp:ListBox>
             <div>
                 <label>Dibuka</label>
                 <asp:ListBox ID="Dibuka1" runat="server" Width="300px" Height="170px"
                              AutoPostBack="True" SelectionMode="Multiple" onchange="updateSubMenuList()"></asp:ListBox>
             </div>
         </div>
     </div>
     <div class="col-md-offset-3 col-md-9" id="panel_btnAll" runat="server" visible="true">
         <asp:Button runat="server" ID="btnSimpan" Text="Simpan" class="fa fa-check" CssClass="btn green" />
         <asp:Button runat="server" ID="btnBatal" Text="Batal"  CssClass="btn red" />
     </div>
</div>

后端VB.NET逻辑完善

1. 菜单实体类

Public Class MenuItem
    Public Property MenuId As Integer
    Public Property MenuName As String
    Public Property ParentId As Integer? ' 主菜单ParentId为Nothing,子菜单对应主MenuId
    Public Property IsEnabled As Boolean ' True=开启,False=锁定
End Class

2. 页面加载与数据绑定

Private originalMenuList As List(Of MenuItem) ' 存储原始权限状态,用于取消功能

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    If Not IsPostBack Then
        ' 从数据库加载所有菜单数据(替换为实际数据访问代码)
        originalMenuList = LoadMenuPermissionsFromDB()
        BindMenuListBoxes(originalMenuList)
        Modul.Visible = True ' 显示权限配置模块
    End If
End Sub

' 绑定菜单到对应的ListBox
Private Sub BindMenuListBoxes(menuList As List(Of MenuItem))
    ' 绑定主菜单
    Dim mainMenus = menuList.Where(Function(m) m.ParentId Is Nothing).ToList()
    Dikunci.Items.Clear()
    Dibuka.Items.Clear()
    For Each menu In mainMenus
        Dim item As New ListItem(menu.MenuName, menu.MenuId.ToString())
        If menu.IsEnabled Then
            Dibuka.Items.Add(item)
        Else
            Dikunci.Items.Add(item)
        End If
    Next

    ' 绑定子菜单
    Dim subMenus = menuList.Where(Function(m) m.ParentId IsNot Nothing).ToList()
    Dikunci1.Items.Clear()
    Dibuka1.Items.Clear()
    For Each menu In subMenus
        Dim item As New ListItem(menu.MenuName, menu.MenuId.ToString())
        If menu.IsEnabled Then
            Dibuka1.Items.Add(item)
        Else
            Dikunci1.Items.Add(item)
        End If
    Next
End Sub

' 模拟从数据库加载权限数据
Private Function LoadMenuPermissionsFromDB() As List(Of MenuItem)
    Return New List(Of MenuItem) From {
        New MenuItem With {.MenuId = 1, .MenuName = "用户管理", .ParentId = Nothing, .IsEnabled = True},
        New MenuItem With {.MenuId = 2, .MenuName = "角色管理", .ParentId = Nothing, .IsEnabled = False},
        New MenuItem With {.MenuId = 3, .MenuName = "用户列表", .ParentId = 1, .IsEnabled = True},
        New MenuItem With {.MenuId = 4, .MenuName = "用户新增", .ParentId = 1, .IsEnabled = True},
        New MenuItem With {.MenuId = 5, .MenuName = "角色列表", .ParentId = 2, .IsEnabled = False}
    }
End Function

3. 主菜单变更同步子菜单

' 主菜单锁定列表变更事件
Protected Sub Dikunci_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Dikunci.SelectedIndexChanged
    SyncSubMenusByMainMenu(Dikunci, False) ' 移动到锁定列表,子菜单同步锁定
End Sub

' 主菜单开启列表变更事件
Protected Sub Dibuka_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Dibuka.SelectedIndexChanged
    SyncSubMenusByMainMenu(Dibuka, True) ' 移动到开启列表,子菜单同步开启
End Sub

' 同步主菜单对应的所有子菜单权限
Private Sub SyncSubMenusByMainMenu(sourceListBox As ListBox, isEnabled As Boolean)
    For Each selectedItem In sourceListBox.SelectedItems.Cast(Of ListItem).ToList()
        Dim mainMenuId = Integer.Parse(selectedItem.Value)
        Dim targetSubList = If(isEnabled, Dibuka1, Dikunci1)
        Dim sourceSubList = If(isEnabled, Dikunci1, Dibuka1)

        ' 遍历子菜单列表,匹配当前主菜单的子项并移动
        For Each subItem In sourceSubList.Items.Cast(Of ListItem).ToList()
            Dim subMenu = originalMenuList.FirstOrDefault(Function(m) m.MenuId = Integer.Parse(subItem.Value))
            If subMenu IsNot Nothing AndAlso subMenu.ParentId = mainMenuId Then
                sourceSubList.Items.Remove(subItem)
                targetSubList.Items.Add(subItem)
            End If
        Next
    Next
    sourceListBox.ClearSelection()
End Sub

4. 保存与取消按钮逻辑

' 保存按钮事件
Protected Sub btnSimpan_Click(sender As Object, e As EventArgs) Handles btnSimpan.Click
    Dim updatedMenuList = New List(Of MenuItem)()

    ' 收集主菜单权限状态
    For Each item In Dikunci.Items.Cast(Of ListItem)()
        updatedMenuList.Add(New MenuItem With {
            .MenuId = Integer.Parse(item.Value),
            .MenuName = item.Text,
            .ParentId = Nothing,
            .IsEnabled = False
        })
    Next
    For Each item In Dibuka.Items.Cast(Of ListItem)()
        updatedMenuList.Add(New MenuItem With {
            .MenuId = Integer.Parse(item.Value),
            .MenuName = item.Text,
            .ParentId = Nothing,
            .IsEnabled = True
        })
    Next

    ' 收集子菜单权限状态
    For Each item In Dikunci1.Items.Cast(Of ListItem)()
        Dim subMenu = originalMenuList.FirstOrDefault(Function(m) m.MenuId = Integer.Parse(item.Value))
        If subMenu IsNot Nothing Then
            updatedMenuList.Add(New MenuItem With {
                .MenuId = subMenu.MenuId,
                .MenuName = item.Text,
                .ParentId = subMenu.ParentId,
                .IsEnabled = False
            })
        End If
    Next
    For Each item In Dibuka1.Items.Cast(Of ListItem)()
        Dim subMenu = originalMenuList.FirstOrDefault(Function(m) m.MenuId = Integer.Parse(item.Value))
        If subMenu IsNot Nothing Then
            updatedMenuList.Add(New MenuItem With {
                .MenuId = subMenu.MenuId,
                .MenuName = item.Text,
                .ParentId = subMenu.ParentId,
                .IsEnabled = True
            })
        End If
    Next

    ' 保存到数据库(替换为实际数据访问代码)
    SaveMenuPermissionsToDB(updatedMenuList)
    originalMenuList = updatedMenuList
    ClientScript.RegisterStartupScript(Me.GetType(), "alert", "alert('权限配置已保存');", True)
End Sub

' 取消按钮事件
Protected Sub btnBatal_Click(sender As Object, e As EventArgs) Handles btnBatal.Click
    ' 重置为原始权限状态
    BindMenuListBoxes(originalMenuList)
    ClientScript.RegisterStartupScript(Me.GetType(), "alert", "alert('已取消所有未保存变更');", True)
End Sub

' 模拟保存到数据库
Private Sub SaveMenuPermissionsToDB(menuList As List(Of MenuItem))
    ' 此处编写实际的数据库更新逻辑
End Sub

前端JS辅助逻辑

在ASPX页面的<script>标签中添加以下代码,优化用户交互体验:

function updateSubMenuList() {
    // 可选:前端预同步子菜单,减少回发等待感
    // 示例逻辑可根据实际需求扩展,后端已处理核心同步逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:21:00