这个月作项目,遇到过一个经过配置文件来生成菜单的解决方案,感受挺优雅的,特意放到博客园来,以飨读者。this
说来惭愧,之前作的项目都没有这样用过,都是固定死了。若是后续有须要加入菜单,还得在从新修改UI,而后提交code,才OK。可是若是经过配置文件的方式进行操做,则能够不用动code,只须要修改配置文件便可。spa
有兴趣的能够往下看,不难,很简单!~code
先看下此次demo的结构:orm
我用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格式文件。blog
ParentMenuId=0表示这是父类,也就是一级菜单!若是是“1”则表示二级菜单,其它的余此类推。继承
FormName:表示窗体的路径ip
MenuName:表示这个窗体所对于的后台逻辑代码!这是一个类继承MenuBase类!get
MenuID:就是一个每一个Menu的ID,在MenuName子类的时候,须要指定。源码
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 = 0, //新窗口打开 TabForm = 1, //Tab页打开 }
就2个Model很简单,字段都是跟XML文件里的字段相对应!
先看代码:
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 > 0) { 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控件中。不然,弹出框!
应该说以上就是一些核心的代码。
怎么使用呢?很简单,在咱们的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 > 0) { BindMenu(0, null); } } private void BindMenu(int parentId, MenuItem item) { List<MenuItemInfo> list = BaseLogic.GetInstanse().MenuList.FindAll(p => p.ParentMenuId == parentId); if (list != null && list.Count > 0) { 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 == 0) { 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); } } }
就是一些绑定操做!~
匆忙写的,不懂的能够在讨论哈!~晚安咯 各位大神!