Winform界面中实现菜单列表的动态个性化配置管理方法

在我们一般的应用系统里面,由于系统是面向不同类型的用户,我们所看到的菜单会越来越多,多一点的甚至上百个,但是我们实际工作接触的菜单可能就是那么几个,那么对于这种庞大的菜单体系,寻找起来非常不便。因此对菜单的个性化配置就显得尤为重要,本篇随笔就是基于这样的理念,提供用户对可见菜单进行一个动态配置,只选自己喜欢、常用的菜单显示出来即可,菜单的配置存储在数据库里面,在不同的客户端体验都是一样。本篇随笔主要介绍实现这样的功能的一个完整思路,部分代码逻辑可供参考。

1、 菜单列表的动态个性化配置的过程

在我们有些软件里面,我们可能在界面上顶部放置菜单,也可能在界面的左侧放置树形列表菜单,这种情况都有可能,本篇摘取其中之一,左侧菜单进行一个介绍菜单的配置处理。

例如我们在左侧根据用户权限展示相关的菜单信息,动态生成整个列表展示,大致的界面效果如下所示。

然后在功能列表上提供一个右键的菜单进行菜单的刷新、配置管理,如下界面所示。

通过配置功能,我们让用户进入一个配置管理界面,在其中配置显示自己感兴趣的菜单,然后进行保存即可,保存后同时刷新界面的功能菜单显示。

以上几个界面效果就是为了介绍整个菜单配置管理的一般过程,之所以把界面效果放在前面介绍,就是能够让我们有一个类似原型设计方式的感性认识,了解了相关的处理过程,我们就可以着手通过编码的方式来实现这个处理逻辑了。

2、菜单动态个性化配置的功能实现

上面介绍了大概的界面效果,有了参考,我们可以把它的实现思路通过代码实现出来。

1)参数的数据存储

首先我们需要了解,用户配置可以通过XML保存在本地,也可以通过数据库存储保存在服务器,后者在分布式的客户端的时候,可以处处一样,这样就不会造成体验上的差异,因此我们这里采用存储在数据库的方案。

这个存储我们沿用我之前介绍过的配置管理组件(SettingsProvider.net),我在随笔《Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建》中对它的使用进行了详细的介绍。

这个配置管理组件SettingsProvider.net使用起来也是比较方便的,可以选择存储在本地的对象,也可以选择存储在数据库的存储对象。

首先我们先定义一个存储的参数类,这个是使用这个组件所必须的存储对象信息,如下代码所示。

/// <summary>
 /// 用来控制人员管理显示菜单的参数配置
 /// </summary>
 public class UserMenuParameter
 {
  [DefaultValue("")]
  [Description("用户ID")]
  public string UserID { get; set; }

  [Description("用户设置可见的菜单")]
  public Dictionary<string, bool> VisibleDict { get; set; }
 }

需要获取或存储这个对象信息的时候,我们初始化几个管理类,如下代码所示。

//参数存储所需的相关对象
private SettingsProvider settings;
private ISettingsStorage store;
private UserMenuParameter parameter;

然后在配置管理界面窗体里面,初始化这几个对象,如下代码所示。

// PortableStorage: 在运行程序目录创建一个setting的文件记录参数数据
// DatabaseStorage:在数据库TB_UserParameter表存储用户配置参数
store = new DatabaseStorage(LoginUserInfo.ID);
settings = new SettingsProvider(store);
parameter = settings.GetSettings<UserMenuParameter>();

这样我们就可以根据用户的ID,获取对应记录的信息并转换为相关的对象了,如果我们需要把修改的信息写会到存储介质里面,代码如下所示。

try
   {
    parameter = settings.GetSettings<UserMenuParameter>();
    parameter.VisibleDict = dict;
    parameter.UserID = LoginUserInfo.ID;
    settings.SaveSettings<UserMenuParameter>(parameter);

    ProcessDataSaved(sender, e);//触发外部事件

    this.DialogResult = System.Windows.Forms.DialogResult.OK;
   }
   catch (Exception ex)
   {
    LogHelper.Error(ex);
    MessageDxUtil.ShowError(ex.Message);
    return;
   }

2)配置管理界面的实现

解决了参数的获取及存储功能后,我们需要编写一个界面来管理用户的菜单配置,也就是我们前面介绍的菜单配置管理界面。

我们这个界面的定义代码如下所示。

其中参数的数据存储就是应用了前面介绍的代码,这里需要根据用户的配置项初始化树形菜单的显示处理,通过InitTree的函数实现菜单的显示。

在显示菜单前,我们先介绍一下功能菜单显示的规则,仅当参数存在对应记录,并且该记录显式设置不可见,菜单才不可见,否则默认菜单是可以看到的。

这样确保了,在参数没有配置前,所有的菜单对当前用户是可见的,只有用户设置为不不可见,该菜单才不显示为不可见。

/// <summary>
  /// 获取菜单是否可见。
  /// 仅当参数存在对应记录,并且该记录显式设置不可见,菜单才不可见,否则默认菜单是可以看到的。
  /// </summary>
  /// <param name="id">菜单ID</param>
  /// <returns></returns>
  private bool GetVisibleMenu(string id)
  {
   bool result = true;
   if (parameter != null)
   {
    var dict = parameter.VisibleDict;
    if(dict != null && dict.ContainsKey(id))
    {
     result = dict[id];
    }
   }
   return result;
  }

显示菜单的相关处理逻辑,就是根据上面的判断,然后确定是否勾选记录,如下代码所示。

存储用户勾选的记录的时候,我们需要遍历整个树节点,判断勾选了那些选项,然后把它保存数据库即可。

/// <summary>
  /// 递归获取选中的树节点集合
  /// </summary>
  /// <param name="node">树节点</param>
  /// <param name="dict">字典集合</param>
  /// <returns></returns>
  private Dictionary<string, bool> GetTreeSelection(TreeNode node, Dictionary<string, bool> dict)
  {
   if (node.Tag != null)
   {
    var check = node.Checked;
    var menuId = string.Concat(node.Tag);
    if(!dict.ContainsKey(menuId))
    {
     dict.Add(menuId, check);
    }
   }

   foreach (TreeNode child in node.Nodes)
   {
    GetTreeSelection(child, dict);
   }

   return dict;
  }

参数的保存操作如下所示。

/// <summary>
  /// 保存用户配置信息
  /// </summary>
  private void btnOK_Click(object sender, EventArgs e)
  {
   //获取用户勾选的树列表,存放在字典集合里面
   var dict = new Dictionary<string, bool>();
   foreach(TreeNode node in this.treeView1.Nodes)
   {
    GetTreeSelection(node, dict);
   }

   try
   {
    //重新获取参数信息,并设置新值后保存
    parameter = settings.GetSettings<UserMenuParameter>();
    parameter.VisibleDict = dict;
    parameter.UserID = LoginUserInfo.ID;
    settings.SaveSettings<UserMenuParameter>(parameter);

    ProcessDataSaved(sender, e);//触发外部事件

    this.DialogResult = System.Windows.Forms.DialogResult.OK;
   }
   catch (Exception ex)
   {
    LogHelper.Error(ex);
    MessageDxUtil.ShowError(ex.Message);
    return;
   }
  }

3)主界面的相关处理

以上处理完成后,我们在主界面的工具栏右键菜单添加一个菜单项,用来进入配置界面的,如下逻辑代码所示。

private void tool_MenuSetting_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
  {
   MenuSetting();
  }
  /// <summary>
  /// 配置菜单项
  /// </summary>
  private void MenuSetting()
  {
   FrmMenuSetting dlg = new FrmMenuSetting();
   dlg.OnDataSaved += (s, arg) =>
   {
    //用户保存参数后,提示用户更新树形列表
    InitToolbar();
   };
   dlg.ShowDialog();
  }

这样界面配置参数并保存后,界面的树形菜单会及时得到更新处理。

另外,我们主界面的树形列表,也要根据配置参数的信息作相关的调整,如果用户配置了不显示某个菜单,那么主界面也要根据配置参数控制显示。

3、总结

以上就是整个菜单列表的动态个性化配置管理的整体思路和实现步骤代码,主要的界面考量还是以用户的视觉来考虑界面的布局和功能,如果在几百个菜单项中寻找几个常用的菜单,每次是一个比较耗时无聊的操作,因此提供一个个性化的界面,根据工作情况的不同,显示一些和自己相关的功能即可。

例如有些情况下,我们的菜单显示,希望通过工具栏的方式进行控制显示,如下界面效果所示。

那么配置维护界面还是差不多,只是我们控制工具栏的显示逻辑有所不同而已,对于RibbonPage及其功能菜单的动态生成处理如下所示。

本篇随笔主要还是希望读者借鉴配置存储和菜单个性化管理的思路,具体的逻辑会因用户界面的不同,使用的控件不同而有所差异,不过总体思路是一致的即可。

例如有些参数的配置管理,可以统一使用一个配置管理界面进行维护,如我之前的随笔介绍的界面功能一样。

以上这篇Winform界面中实现菜单列表的动态个性化配置管理方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C#实现Winform动态添加菜单的方法

    本文实例讲述了C#实现Winform动态添加菜单的方法.分享给大家供大家参考.具体分析如下: 最近在做WINFORM开发,一直都在为主界面的点击事件及动态加载菜单苦脑.现在已解决这个问题了,可以实现数据库或都XML等配置完成动态生成菜单及事件加载.代码如下: private void Form1_Load(object sender, EventArgs e) { //添加菜单一 ToolStripMenuItem subItem; subItem = AddContextMenu("入库&qu

  • Winform界面中实现通用工具栏按钮的事件处理方法

    在一个给客户做的项目中,界面要求修改增加通用工具栏按钮的事件处理,也就是在主界面中放置几个固定的功能操作按钮,打开不同的页面的时候,实现对应页面的功能处理,这种和我标准的界面处理方式有所不同,标准的列表界面,一般在界面中放置了一些常规的按钮,如查询/更新.新建.编辑.删除.导入.导出等常规操作,现在是需要把这些提升到主界面的层次上放置按钮,这种处理方式也算是提供一种方便吧.本篇随笔介绍实现这个功能的思路和代码实现逻辑. 1.界面功能介绍 这里要实现的通用工具栏按钮的事件处理,具体的界面是这样的,

  • Winform界面中实现菜单列表的动态个性化配置管理方法

    在我们一般的应用系统里面,由于系统是面向不同类型的用户,我们所看到的菜单会越来越多,多一点的甚至上百个,但是我们实际工作接触的菜单可能就是那么几个,那么对于这种庞大的菜单体系,寻找起来非常不便.因此对菜单的个性化配置就显得尤为重要,本篇随笔就是基于这样的理念,提供用户对可见菜单进行一个动态配置,只选自己喜欢.常用的菜单显示出来即可,菜单的配置存储在数据库里面,在不同的客户端体验都是一样.本篇随笔主要介绍实现这样的功能的一个完整思路,部分代码逻辑可供参考. 1. 菜单列表的动态个性化配置的过程 在

  • Android中选项菜单(OptionMenu)的创建方法

    使用OptionMenu 只要重写两个方法 public boolean onCreateOptionsMenu(Menu menu):菜单的初始化 public boolean onOptionsItemSelected(MenuItem item):菜单响应事件 除此之外,还有三个方法可以重写 public void onOptionsMenuClosed(Menu menu):菜单关闭时调用 public boolean onPrepareOptionsMenu(Menu menu):选项

  • javascript中兼容主流浏览器的动态生成iframe方法

    以下代码在IE8下运行通过,在IE9中出错: 复制代码 代码如下: document.createElement('<iframe id="yige-org-iframe" src="yige.org.logo.gif" style="position:absolute;top:0;left:0;width:1px;height:1px;visibility:hidden;"></iframe>'); 错误提示:excep

  • 在Oracle PL/SQL中游标声明中表名动态变化的方法

    /*     小弟刚刚接触ORACLE存储过程,有一个问题向各位同行求教,小弟写了一个存储过程,其目的是接收一个参数作为表名,然后查询该表中的全部记录的某一个字段的内容导入到另一个表中.     (     tabname in varchar     )     is     v_servicesname tabname.服务类型%type; --这个变量就是用来存放所要取得的字段内容,但不知该如何定义     cursor curSort1 is select 服务类型 from tabna

  • SpringBoot实现redis缓存菜单列表

    因为系统的菜单列表是不轻易改变的,所以不需要在每次请求的时候都去查询数据库,所以,在第一次根据用户id请求到菜单列表的时候,可以把菜单列表的数据缓存在redis里,在第二次请求菜单列表的时候,可以直接在redis缓存里面获取数据,从而减少对数据库的操作,提升性能!首先,我们要下载redis到本地,然后在cmd终端打开redis的src目录,然后运行redis-server即可开启redis本地服务(mac),开启了redis服务后,就要在项目中配置相关的redis的代码了,首先在pom.xml中

  • 在Winform框架界面中改变并存储界面皮肤样式的方法

    在本篇介绍的Winform界面样式改变及存储操作中,是指基于DevExpress进行界面样式的变化.一般情况下,默认我们会为客户提供多种DevExpress的界面皮肤以供个人喜好选择,默认DevExpress提供40余种皮肤样式,用户可以根据自己的喜好,选择较为美观.得体的皮肤,为了方便,我们对用户的皮肤选择进行记录,并可以动态改变. 1.界面皮肤的选择 Winform开发框架(包括混合式Winform开发框架)皮肤如下界面所示. 在皮肤集合中打开,可以看到很多界面皮肤可供选择 上面初始化的皮肤

  • vue如何从后台获取数据生成动态菜单列表

    目录 1.数据准备 2.选择组件 3.配置路由 4.不出问题这样就可以实现动态路由了 5.完整代码 1.数据准备 树形菜单基本数据很简单,只需要菜单id,菜单名称,路由地址,图标.下图中的节点id和父节点id是为了后端生成树形数据,只负责前端的话只需要拿到前面说的四个数据就行. 后端将数据转成树形结构,传给前端的数据结构如图 2.选择组件 我直接用element-ui的el-menu组件,结构是(这是用来注释的,完整代码在后面) <el-menu> <template v-for=&qu

  • 在WinForm应用程序中快速实现多语言的处理的方法

    在国际化环境下,越来越多的程序需要做多语言版本,以适应各种业务需求的变化.在Winform应用程序中实现多语言也有常规的处理方式处理,不过需要针对每个语言版本,重新修改Winform界面的显示,对一些常规的辅助类,也需要引入一个统一的资源管理类来处理多语言的问题,相对比较繁琐.本篇随笔针对多语言的需求,希望尽量避免繁琐的操作,既能符合本地语种开发人员的开发习惯,又能快速实现Winform程序的多语言场景处理. 1.多语言开发的困惑和思路 在常规的多语言版本程序中,开发总是伴随着很多不愉快的事情,

  • android中选中菜单的显示跳转和隐式跳转的实例介绍

    查了好多资料,现发还是不全,干脆自己整理吧,至少保证在我的做法正确的,以免误导读者,也是给自己做个记录吧! 简介 android供给了三种菜单类型,分别为options menu,context menu,sub menu. options menu就是通过按home键来表现,context menu需要在view上按上2s后表现.这两种menu都有可以参加子菜单,子菜单不能种不能嵌套子菜单.options menu最多只能在幕屏最下面表现6个菜单项选,称为iconmenu,icon menu不

随机推荐