这个月做项目,遇到过一个通过配置文件来生成菜单的解决方案,感觉挺优雅的,特地放到博客园来,以飨读者。
说来惭愧,以前做的项目都没有这样用过,都是固定死了。如果后续有需要加入菜单,还得在重新修改UI,然后提交code,才OK。但是如果通过配置文件的方式进行操作,则可以不用动code,只需要修改配置文件即可。
有兴趣的可以往下看,不难,很简单!~
先看下这次demo的结构:
1。生成XML式的配置文件菜单项。。
我用XML格式来存储,
<MenuList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<language>zh-ch</language>
<displayName>Simplified_Chinese</displayName>
<version>1.0</version>
<author>Crystal</author>
<MenuItem Name="Trade" HeaderText="交易" MenuId="1" ParentMenuId="0">
<MenuItem Name="CommodityTrade" HeaderText="商品交易" MenuId="11" ParentMenuId="1" FormName="TestMenu.Menu.MenuForm.Trade.CommodityTrade" MenuName="TestMenu.Menu.MenuLogical.Trade.CommodityTradeMenu" OpenType="0"></MenuItem>
<MenuItem Name="ConditionTrade" HeaderText="条件下单" MenuId="12" ParentMenuId="1" FormName="TestMenu.Menu.MenuForm.Trade.ConditionTrade" MenuName="TestMenu.Menu.MenuLogical.Trade.ConditionTradeMenu" OpenType="1"></MenuItem>
<MenuItem Name="DeliveryTrade" HeaderText="交割申报" MenuId="13" ParentMenuId="1" FormName="TestMenu.Menu.MenuForm.Trade.DeliveryTrade" MenuName="TestMenu.Menu.MenuLogical.Trade.DeliveryTradeMenu" OpenType="1"></MenuItem>
</MenuItem>
<MenuItem Name="Bank" HeaderText="银行" MenuId="2" ParentMenuId="0">
<MenuItem Name="BankSign" HeaderText="银行签约" MenuId="21" ParentMenuId="2"></MenuItem>
<MenuItem Name="BankUnSign" HeaderText="银行解约" MenuId="22" ParentMenuId="2"></MenuItem>
</MenuItem>
<MenuItem Name="Fund" HeaderText="资金" MenuId="3" ParentMenuId="0">
<MenuItem Name="FundInOut" HeaderText="出入金" MenuId="31" ParentMenuId="3"></MenuItem>
<MenuItem Name="FundTransfer" HeaderText="资金转移" MenuId="32" ParentMenuId="3"></MenuItem>
</MenuItem>
<MenuItem Name="Help" HeaderText="帮助" MenuId="9" ParentMenuId="0">
<MenuItem Name="HelpHotKey" HeaderText="热键帮助" MenuId="91" ParentMenuId="9" FormName="" MenuName="" OpenType="0"></MenuItem>
<MenuItem Name="HelpNormalQues" HeaderText="常见问题" MenuId="92" ParentMenuId="9" FormName="" MenuName="" OpenType="0"></MenuItem>
<MenuItem Name="HelpTelphone" HeaderText="电话服务" MenuId="93" ParentMenuId="9" FormName="" MenuName="" OpenType="0"></MenuItem>
<MenuItem Name="HelpProductBook" HeaderText="产品说明书" MenuId="94" ParentMenuId="9" FormName="" MenuName="" OpenType="0"></MenuItem>
<MenuItem Name="HelpAbout" HeaderText="关于产品" MenuId="95" ParentMenuId="9"></MenuItem>
</MenuItem>
</MenuList>
通过上面我们知道,这是一个标准的XML格式文件。
ParentMenuId=0表示这是父类,也就是一级菜单!如果是“1”则表示二级菜单,其它的余此类推。
FormName:表示窗体的路径
MenuName:表示这个窗体所对于的后台逻辑代码!这是一个类继承MenuBase类!
MenuID:就是一个每个Menu的ID,在MenuName子类的时候,需要指定。
2。两个实体类:MenuInfo和MenuItemInfo
MenuInfo:
[Serializable]
[XmlRoot("MenuList")]
public class MenuInfo
{
[XmlElement("language")]
public string Language { get; set; } [XmlElement("displayName")]
public string DisplayName { get; set; } [XmlElement("version")]
public string Version { get; set; } [XmlElement("author")]
public string Author { get; set; } [XmlElement("MenuItem")]
public List<MenuItemInfo> MenuItemList { get; set; }
}
MenuItemInfo:
[Serializable]
public class MenuItemInfo
{
[XmlAttribute("Name")]
public string Name { get; set; } [XmlAttribute("HeaderText")]
public string HeaderText { get; set; } [XmlAttribute("MenuId")]
public int MenuId { get; set; } [XmlAttribute("ParentMenuId")]
public int ParentMenuId { get; set; } [XmlAttribute("FormName")]
public string FormName { get; set; } [XmlAttribute("MenuName")]
public string MenuName { set; get; } [XmlAttribute("OpenType")]
public int OpenType { get; set; } [XmlElement("MenuItem")]
public List<MenuItemInfo> MenuItemList { get; set; }
} public enum OpenType
{
NewForm = , //新窗口打开
TabForm = , //Tab页打开
}
就2个Model很简单,字段都是跟XML文件里的字段相对应!
3.。所有Menu的基类---MenuBase
先看代码:
public class MenuBase
{
public MenuItemInfo menuItemInfo;
public MenuBase()
{
}
public MenuBase(int menuId)
{
this.menuItemInfo = BaseLogic.GetInstanse().MenuList.Find(p => p.MenuId == menuId);
}
public virtual void Excute(TabControl tabControl)
{
if (!string.IsNullOrEmpty(this.menuItemInfo.FormName))
{
if (this.menuItemInfo.OpenType == (int)OpenType.NewForm) //新窗口打开
{
Window billForm = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(this.menuItemInfo.FormName, false) as Window;
billForm.ShowDialog();
billForm.Close();
}
else if (this.menuItemInfo.OpenType == (int)OpenType.TabForm) //Tab页打开
{
CloseableTabItem tab = null;
// TabItem tab = null;
if (tabControl.Items.Count > )
{
foreach (CloseableTabItem item in tabControl.Items)
{
if (item.Name == this.menuItemInfo.Name)
{
tab = item;
break;
}
}
}
if (tab == null)
{
var v = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(this.menuItemInfo.FormName, false);
//tab = new TabItem();
tab = new CloseableTabItem();
tab.Name = this.menuItemInfo.Name;
tab.Header = this.menuItemInfo.HeaderText;
//tab.Tag = this.menuItemInfo.MenuName;
tab.Content = v; tabControl.Items.Add(tab);
}
tab.IsSelected = true;
}
}
}
}
这是一个关键基类,每一个菜单所对应的后台逻辑页面,都要继承MenuBase基类!~
通过上面介绍XML的时候,我们知道有一个字段是“MenuID”。这个MenuID就是在实现MenuBase的时候,通过base 传入到基类。然后基类通过下面code进行查询到相对于页面信息:
this.menuItemInfo = BaseLogic.GetInstanse().MenuList.Find(p => p.MenuId == menuId);
Execute是一个虚方法,子类进行调用。它有一个参数就是TabControl,如果OpenType(一个枚举值,是一个窗体还是一个Tab)的是一个Tab值,那么就把这个页面加入到TabControl控件中。否则,弹出框!
应该说以上就是一些核心的代码。
4.。怎么用呢?
怎么使用呢?很简单,在我们的XAML中 放入如下东东:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30px" />
<RowDefinition />
</Grid.RowDefinitions>
<Menu Name="MainMenu">
</Menu>
<TabControl Name="tabDown" TabStripPlacement="Bottom" Grid.Row="1">
</TabControl>
</Grid>
后台:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//加载菜单!
if (BaseLogic.GetInstanse().MenuList != null && BaseLogic.GetInstanse().MenuList.Count > )
{
BindMenu(, null);
}
}
private void BindMenu(int parentId, MenuItem item)
{
List<MenuItemInfo> list = BaseLogic.GetInstanse().MenuList.FindAll(p => p.ParentMenuId == parentId);
if (list != null && list.Count > )
{
foreach (MenuItemInfo info in list)
{
MenuItem menuItem = new MenuItem();
menuItem.Name = info.Name;
menuItem.Header = info.HeaderText;
menuItem.Tag = info;
menuItem.Click += new RoutedEventHandler(menuItem_Click);
if (parentId == )
{
this.MainMenu.Items.Add(menuItem);
}
else
{
item.Items.Add(menuItem);
}
BindMenu(info.MenuId, menuItem);
}
}
} private void menuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem; string menuName = ((MenuItemInfo)(item.Tag)).MenuName;
//string fullName = menuName;
//MenuBase menuBase = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string.Format("ygPlatForm.Logic.MenuLogic.{0}Menu", item.Name), false) as MenuBase;
if (menuName != null)
{
MenuBase menuBase = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(menuName, true) as MenuBase;
if (menuBase != null)
menuBase.Excute(this.tabDown);
}
}
}
就是一些绑定操作!~
5.。结果
匆忙写的,不懂的可以在讨论哈!~晚安咯 各位大神!
WPF+通过配置文件生成菜单(Menu)+源码的更多相关文章
-
Ocelot简易教程(七)之配置文件数据库存储插件源码解析
作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9852711.html 上篇文章给大家分享了如何集成我写的一个Ocelot扩展插件把Ocelot的配置存储 ...
-
开源方案搭建可离线的精美矢量切片地图服务-8.mapbox 之sprite大图图标文件生成(附源码)
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
-
H5类似易企秀/编辑器/页面制作/开发/生成工具/软件/源码/授权
代码地址如下:http://www.demodashi.com/demo/14960.html 项目简介 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具. ...
-
C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)
C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...
-
jQuery实现多级手风琴树形下拉菜单(源码)
前几天因为公司的菜单要调整,公司的UI框架是不支持的,所以就自己在网上找了一个下拉菜单,可以支持多级菜单数据的,菜单数据是从xml文件中配置后读取的,网上有许多这方面的例子感觉不是很好用,就打了个包贴 ...
-
【krpano】二维码自动生成插件(源码+介绍+预览)
简介 在krpano生成的全景支持HTML5在手机中展示,而在手机中打开全景网址时不方便,需要输入网址. 最近研究了如何让krpano全景根据自己当前的网址,自动生成二维码,并在电脑浏览时,可以展示出 ...
-
轻量级验证码生成插件webutil-licenseImage源码与实例应用
webutil-licenseImage 插件内置4种验证码样式,支持用户扩展.自定义样式实现简单验证码. 源码脱管地址: http://code.google.com/p/licenseimage/ ...
-
python生成可执行文件保护源码
工作中由于需要防止源代泄漏,需要将源代码隐藏,找到两种方法: 1.使用python生成的pyc文件. 这种方法的优点就是pyc文件生成很容易,缺点则是很容易通过工具得到源码,并且python版本不一致 ...
-
Spark streaming技术内幕6 : Job动态生成原理与源码解析
原创文章,转载请注明:转载自 周岳飞博客(http://www.cnblogs.com/zhouyf/) Spark streaming 程序的运行过程是将DStream的操作转化成RDD的操作,S ...
随机推荐
-
asp.net Get和Post传参和接收参数
asp.netGet和Post传参和接收参数 Get请求: 对于传参:test.aspx?name=%e5%bc%a0%e4%b8%89 接收参数的方法: Request.QueryString[&q ...
-
apt-get命令学习
在windows下安装软件,我们只需要有EXE文件,然后双击,下一步直接OK就可以了.但在LINUX下,不是这样的.每个LINUX的发行版,比如UBUNTU,都会维护一个自己的软件仓库,我们常用的几乎 ...
-
在Mvc中进行异步请求是出现(没有为该对象定义无参数的构造函数)
解决办法就是给相应的类添加无参数的构造函数:
-
No application encryption key has been specified.
环境:php7.1.10laravel5.5出现: 解决:在根目录下执行: php artisan key:generate OK问题解决
-
【MySQL】随机获取数据的方法,支持大数据量
在mysql中带了随机取数据的函数,在mysql中我们会有rand()函数,很多朋友都会直接使用,如果几百条数据肯定没事,如果几万或百万时你会发现,直接使用是错误的.下面我来介绍随机取数据一些优化方法 ...
-
Jupyter 快速入门——写python项目博客非常有用!!!
from:https://blog.csdn.net/m0_37338590/article/details/78862488 一.简介: Jupyter Notebook(此前被称为 IPython ...
-
初级字典树查找在 Emoji、关键字检索上的运用 Part-1
系列索引 Unicode 与 Emoji 字典树 TrieTree 与性能测试 生产实践 前言 通常用户自行修改资料是很常见的需求,我们规定昵称长度在2到10之间.假设用户试图使用表情符号
-
anu - react
import { options } from "./util"; import { Children } from "./Children"; import ...
-
[转]修改DLL
部分内容来自:http://blog.csdn.net/csdncshuan/article/details/51477705 为没有源码的DLL文件添加强名称 如果项目中引用了其他没有源码的dll文 ...
-
OpenCL入门:(三:GPU内存结构和性能优化)
如果我们需要优化kernel程序,我们必须知道一些GPU的底层知识,本文简单介绍一下GPU内存相关和线程调度知识,并且用一个小示例演示如何简单根据内存结构优化. 一.GPU总线寻址和合并内存访问 假设 ...