zoukankan      html  css  js  c++  java
  • WPF+通过配置文件生成菜单(Menu)+源码

    这个月做项目,遇到过一个通过配置文件来生成菜单的解决方案,感觉挺优雅的,特地放到博客园来,以飨读者。

    说来惭愧,以前做的项目都没有这样用过,都是固定死了。如果后续有需要加入菜单,还得在重新修改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 = 0,              //新窗口打开
            TabForm = 1,              //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 > 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控件中。否则,弹出框!

    应该说以上就是一些核心的代码。

    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 > 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);
                }
            }
        }

    就是一些绑定操作!~

    5.。结果

    匆忙写的,不懂的可以在讨论哈!~晚安咯 各位大神!

    猛击源码下载

  • 相关阅读:
    Python——GUI编程 控件及常用信号
    Python——PYQT:控件基本使用
    Android 自己定义圆圈进度并显示百分比例控件(纯代码实现)
    Parallel and Perpendicular
    策略模式(Strategy Pattern)
    Linux Framebuffer驱动剖析之中的一个—软件需求
    Java知识总结---整合SpringMVC+Mybatis+Spring(二)
    wav音频文件头解析
    【EasyUi DataGrid】批量删除
    Spark SQL Catalyst源代码分析之UDF
  • 原文地址:https://www.cnblogs.com/damonlan/p/4735371.html
Copyright © 2011-2022 走看看