zoukankan      html  css  js  c++  java
  • operamasksui2.0 +MVC4.0+EF5.0实战之二 功能菜单及树形控件(Tree)

      上篇中介绍了使用omBorderLayout控件实现了系统总体布局,下面我们就来说一下使用树形控件Tree来实现布局左侧区域的功能菜单(注:本文中不考虑功能菜单的权限控制,此部分内容待日后加上)。

      功能菜单是一个系统必不可少的部分,通常包括两级,第一级通常为模块名称,第二级为功能名称,复杂的系统往往会进一步扩展到三级甚至四级。对于软件系统,这是一种常见模式,实体通过自关联,实现无限极扩展,前台通过树形控件来展现。 

      采用树形控件对数据进行展现,有两种选择,一种是一次性读取所有数据,另一种是逐级加载。对于一个系统的功能菜单来说,充其量也就是几十项,一次性读取出来,也完全没有性能问题,因此没必要采取异步方式,逐级加载。对于小数据量,采取逐级异步加载方式,需要频繁访问后台以及进行数据库读取,一般来说,反而会比一次性读取消耗更多的资源。

      首先说一下前台需要做的工作,在Home控制器的Index视图里,做以下操作:

      1.在head标签内部加入对om相关css样式表的引用

        @Styles.Render("~/OperaMasksUI/css/default/om-default.css")     

      2.在</body>标签之前加入以下对js文件的引用

          @Scripts.Render("~/OperaMasksUI/js/jquery163.min.js")

              @Scripts.Render("~/OperaMasksUI/js/operamasks-ui200.min.js")

      3.在前面布局控件的左侧区域中,加入一个ul元素,如下所示

            <div id="west-panel">

                <ul id="tree"></ul>

            </div>

      4.编写js如下:  

         //初始化
            $(function ()
            {
                //初始加载
                LoadLayout();//上节已说的布局控件
                LoadTree();//本节正在说的树控件
                LoadTabs();//下节将要说的tab控件 
            }); 
        function LoadTree()
            {
                $("#tree").omTree({
                    simpleDataModel: true,
                    dataSource: '@Url.Action("GetMenu")',
                    onClick: TreeNodeClick
                });
            }

      treenode 支持两种json格式。
      第一种为:

    {
        text:'node1', // 树节点显示文本,必需
        expanded:true, // 是否默认展开,非必须,默认值是false
        classes:'folder', // 树节点样式,非必需,默认有folder和file,如果用户自定制为其他,则显示用户自定义样式
        children:childrenDataArray, //子节点,非必需。缓加载时可以没有这个属性 
        hasChildren: false // 是否有子节点,非必需,如果值为true表示要缓加载此时可以没有children属性
    } 

      第二种为:

    {
        id:'n1', //树节点的标识,必需
        pid: 'n0' //父节点id,非必需,如果没有设置该节点就为根节点
        text:'node1', // 树节点显示文本,必需
        expanded:true, // 是否默认展开,非必须,默认值是false
        classes:'folder' // 树节点样式,非必需,默认有folder和file,如果用户自定制为其他,则显示用户自定义样式
    } 

      在这里我使用了第二种方式,即指明父节点(pid)方式,特别注意,采用这种方式,需要将simpleDataModel属性设置为true。dataSource属性可以是静态的json对象,也可以是远程的服务器地址,这里我使用了@Url.Action调用了一个后台方法GetMenu来获取数据。至于onClick: TreeNodeClick,这里是指定树节点点击后进行处理的函数,将在下节里跟tab控件一起进行说明,你这里可以写一个简单alert来查看效果 function TreeNodeClick(node,event){alert(“点击:”+node.id);}。 

      

      上面说的都是关于前台的操作,下面说一下后台相关操作。 

      采用Code First模式,首先创建菜单实体  

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Model.Sys
    {
        public class Menu
        {
            [DisplayName("内码")]
            public string ID { get; set; }
    
            [DisplayName("名称")]
            public string Name { get; set; }
    
            [DisplayName("地址")]
            public string Url { get; set; }
    
            [DisplayName("上级内码")]
            public string ParentID { get; set; }
    
            public virtual Menu ParentMenu { get; set; }
    
            [ForeignKey("ParentID")]
            public virtual ICollection<Menu> SonMenus { get; set; }
    
        }
    }

      然后在数据库里插入几条测试数据(以下是使用EntityFramework的迁移功能,在Configuration类的Seed方法里加入测试数据,关于迁移功能请参见我之前的一篇译稿前半部分 Asp.Net MVC4.0 官方教程 入门指南之八--为Movie模型和库表添加字段),当然你也可以在数据库里手工添加。           

    context.Menu.AddOrUpdate
    ( p
    => p.ID, new Menu { ID = "2", Name = "系统管理" }, new Menu { ID = "3", Name = "部门管理", ParentID = "2", Url = "/Sys/Department/ListPage" }, new Menu { ID = "4", Name = "人员管理", ParentID = "2" }, new Menu { ID = "5", Name = "菜单管理", ParentID = "2" }
    );

      为了构建om树节点对应的json数据,新定义一个类,名字就叫TreeNode  

        public class TreeNode
        {
            public string id { get; set; }
            public string pid { get; set; }
            public string text { get; set; }
            public string expanded { get; set; }
            public string classes { get; set; }
            public string url { get; set; }
        }

      url是我自己附加的额外属性,用于指明链接地址的,其他几项是官方标准属性,一看名字就知道大概含义了,在om主页中可以查看具体说明、含义和取值范围。

      最后来看一下位于Home控制器里的GetMenu方法      

         public ActionResult GetMenu()
            {
                IQueryable<Menu> menu = MenuService.Query();
                var nodes = new List<TreeNode>();
                foreach (var item in menu.ToList())
                {
                    TreeNode node = new TreeNode();
                    node.id = item.ID;
                    node.pid = item.ParentID;
                    node.text = item.Name;
                    node.url = item.Url;
                    node.expanded = "true";              
                    nodes.Add(node);
                }
                return Content(nodes.ToJsonString());           
            }

      上面这个方法中第一句是调用了我后台服务方法,实质等同于EF上下文对象context.Menu.AsQueryable(),即取得所有数据。至于最后一句,则是使用了扩展方法,给object对象加了一个ToJsonString()方法,这样就可以像调用ToString()方法一样进行json转换了。

    using System;
    using System.Text;
    using System.Web.Script.Serialization;
    
    
    namespace Common.Extentions
    {
        public static class ObjectExtentions
        {
            public static string ToJsonString(this Object obj)
            {
                JavaScriptSerializer s = new JavaScriptSerializer();
                StringBuilder sb = new StringBuilder();
                s.Serialize(obj, sb);
                return sb.ToString();
            }
        }
    }
  • 相关阅读:
    Strange RadioButton group behavior with ToolBar
    在XAML中为ItemsControl定义分组,适合mvvm绑定
    如何编写无法维护的代码 让自己稳拿铁饭碗 ;-)
    WPF 应用程序资源、内容和数据文件
    XNA+WPF solution worked
    object转List<XXX>的问题
    VS2013 执行Enable-Migrations,产生错误的解决办法
    WPF 为 PasswordBox 控件添加水印,最低级版
    为 ItemsControl 类型的控件提供行号,mvvm模式 绑定集合
    把父窗体设置为桌面,显示桌面时程序仍然能显示
  • 原文地址:https://www.cnblogs.com/seawaving/p/2891017.html
Copyright © 2011-2022 走看看