zoukankan      html  css  js  c++  java
  • WinForm企业应用框架设计【三】框架窗体设计;动态创建菜单;

    要不是我的朋友乔乔==乔不死跟我聊到领域驱动设计~

    我也不会发现第一篇中关于“充血实体”的错误说法(至少~我写文章的时候~内心的想法是错的~)

    我个人不是很喜欢领域驱动设计~感觉这种思路(我们暂且叫它思路~虽然它有一些既有的原则和模式)

    重点要求架构师深入到业务领域中去~

    但是在国内往往很难真正的与领域专家做深入交流~

    架构师划分的领域模型和聚合往往与真实的情况差别较大~

    即使划分的较好~新的业务和变化的业务也另设计师非常头疼~

    另外

    设计师很难将庞大复杂的业务抽象成领域模型

    往往需要引入更为复杂的模型以对真实业务进行建模

    -----------

    xuefly说多放点内容出来~好吧~这次多一些(多了吗?)~

    奔放的胸毛 等好几个朋友都对源码比较感兴趣~

    我看你们都是娈童癖~这玩意还没发育成熟~就拿过去搞~有啥意思~

    我下一章打算写“登录;闪屏;客户端数据缓存;WCF安全验证”

    (这些东西的代码还没个影子)

    ----------------------

    问题一:关于调试

    如果你的跟着我的章节在做练习~

    那么你可能会遇到从客户端单步调试进入到WCF端的过程

    我的WCF是直接用的IIS7.5的虚拟目录

    单步跳入WCF之前会提示

    直接点[附加]就可以调试了~

    问题二:关于创建动态WCF服务不完善的地方

    在本系列第一篇中,我们使用了众多servicefactory来创建服务;这样是不好的

    我对那段代码做了修改

    请看这里:http://www.cnblogs.com/liulun/archive/2011/11/29/2268337.html

     

    好吧!言归正传

    一:框架窗体

    先看图片 

    框架窗体分管布局的只有四个Panel;

    上、下、左、右。(搞过EXTJS的人比较喜欢说成东、南、西、北)-_-!

    最上面的Panel是存放顶级菜单用的 (top menu)

    最下面的panel是存放状态信息和系统版本用的

    左边的Panel又分为两个panel

    上面的是sub menu header 

    下面的是sub menu

    当点击一个top menu之后,sub menu中将出现所有此top menu下的子菜单

    sub menu header就是这个top menu的名字

    (因为我们的top menu没有选中状态;所以这里做一个sub menu header;让用户知道他点的是哪个顶菜单;sub menu就有选中状态了)

    右侧的Panel也分为两个Panel

      上面的是tabs

      下面的是child form

       tabs是为了存放用户打开过的业务窗体的标题;当用户点击某个tab,将激活该窗体(在child form中显示)

      child form是当前正在操作的业务窗体

      (这里有例子会容易理解一些)

    左右panel中间夹着一个splitter

    此splitter可以拖动改变左右panel的宽度

    这里需要注意一点

    应该先把左侧panel拖进窗体,设置Dock left,

    再拖一个splitter进窗体,他是天然的Dock left,

    再拖右侧panel进窗体,设置Dock fill

    这样splitter才会起作用

    至于怎么把其他panel拖动到这个窗体中来~我就不多说了

    二:动态创建顶部菜单

    上一章中我们成功的访问WCF并得到了所有的MENU

    现在我们就准备在界面上显示菜单 

            private void MainForm_Load(object sender, EventArgs e)
            {
                if (!Utils.IsInDesignMode())
                {
                    InitMenu();
                }
            }
    

    IsInDesignMode是为了判断当前的窗体是不是出于设计状态

    (设计状态会执行一些代码~如果不进行处理~窗体就无法设计)

    代码如下~

            /// <summary>
            /// 判断是否为设计状态
            /// </summary>
            /// <returns></returns>
            public static bool IsInDesignMode()
            {
                bool returnFlag = false;
                #if DEBUG
                if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
                {
                    returnFlag = true;
                }
                else if (System.Diagnostics.Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV"))
                {
                    returnFlag = true;
                }
                #endif
                return returnFlag;
            }
    

    由于创建菜单~和响应菜单的点击事件需要很多代码

    我们把这些与菜单相关的代码统一放在一个partial类里

            /// <summary>
            /// 菜单缓存
            /// </summary>
            public List<MenuModel> Menus;
            /// <summary>
            /// 初始化菜单
            /// </summary>
            private void InitMenu()
            {
                PrepareMenus();
                CreateTopMenu();            
            }
            /// <summary>
            /// 从WCF获取所有菜单
            /// </summary>
            private void PrepareMenus()
            {
                var factory = new Common.ClientFactory<IMenu>();
                try
                {
                    var client = factory.CreateClient();
                    Menus = client.GetAllMenu();
                }
                catch (Exception ex)
                {
                    Utils.OnException(ex);
                }
                factory.Dispose();
            }
    

    如你所见~我已经对上一章中写的PrepareMenus做了一些修改~这些修改是为下一章服务~现在先不讲

    先看CreateTopMenu

            /// <summary>
            /// 创建顶部菜单
            /// </summary>
            private void CreateTopMenu()
            {
                var tmms = (from v in Menus where v.ParentId == Guid.Empty orderby v.OrderNum select v).ToList();
                for (var i = 0; i < tmms.Count; i++)
                {
                    var ctl = CreateOneTopMenu(tmms[i], i);
                    TopMenuP.Controls.Add(ctl);
                }
            }
            /// <summary>
            /// 创建一个顶部菜单
            /// </summary>
            /// <param name="m"></param>
            /// <param name="index"></param>
            /// <returns></returns>
            private Control CreateOneTopMenu(MenuModel m, int index)
            {
                var tm = new Label();
                tm.Width = 68;
                tm.Height = 40;
                tm.Text = m.MenuName;
                tm.TextAlign = ContentAlignment.MiddleCenter;
                tm.BackColor = Color.Transparent;
                tm.Left = index * 68 + index * 12 + 12;
                tm.Top = 9;
                tm.Cursor = Cursors.Hand;
                tm.Tag = m;
                tm.MouseEnter += new EventHandler(tm_MouseEnter);
                tm.MouseLeave += new EventHandler(tm_MouseLeave);
                tm.MouseUp += new MouseEventHandler(tm_MouseUp);
                return tm;
            }
    

    对啦!顶部菜单就是一个label!

    这些label创建出来之后,全部把他们放到TopMenuP这个panel了

    这个panel就是顶部panel

    tm.Left = index * 68 + index * 12 + 12;

    这一句的作用是把这些顶级菜单依次排开~避免覆盖~

    另外我把MenuModel的实例赋值给这个label的Tag属性了~后面有用

    我为这些label注册了同样的鼠标划入、划出、弹起 事件

    现在就看看这些事件

            /// <summary>
            /// 顶部菜单鼠标滑出
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void tm_MouseLeave(object sender, EventArgs e)
            {
                var lb = sender as Label;
                lb.BackColor = Color.Transparent;
                lb.ForeColor = SystemColors.ControlText;
            }
            /// <summary>
            /// 顶部菜单鼠标滑入
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void tm_MouseEnter(object sender, EventArgs e)
            {
                var lb = sender as Label;
                lb.BackColor = Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(96)))), ((int)(((byte)(130)))));
                lb.ForeColor = Color.White;
            }
            /// <summary>
            /// 顶部菜单鼠标弹起
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void tm_MouseUp(object sender, MouseEventArgs e)
            {
                var lb = sender as Label;
                var m = lb.Tag as MenuModel;
                CreateSubMenu(m);
            }
    

    顶部菜单划出和划入都没有什么特别的

    只不过是改变了这个label的背景颜色和文字颜色

    注意:这些颜色的值~应该放到资源或者缓存里去~

    鼠标弹起事件~就说明客户点击了这个lable

    我们把tag属性转换成MenuModel

    然后就开始创建子菜单了

    三:动态创建子菜单

    代码如下

            /// <summary>
            /// 创建子菜单
            /// </summary>
            /// <param name="tm"></param>
            private void CreateSubMenu(MenuModel tm)
            {
                SubHeaderLB.Text = tm.MenuName;
                SubMenuP.Controls.Clear();
                var smms = (from v in Menus where v.ParentId == tm.Id orderby v.OrderNum select v).ToList();
                for (var i = 0; i < smms.Count; i++)
                {
                    var ctl = CreateOneSubMenu(smms[i], i);
                    SubMenuP.Controls.Add(ctl);
                }
            }
            /// <summary>
            /// 创建一个子菜单
            /// </summary>
            /// <param name="m"></param>
            /// <param name="index"></param>
            /// <returns></returns>
            private Control CreateOneSubMenu(MenuModel m, int index)
            {
                var sm = new Label();
                sm.Width = SubHeaderLB.Width;
                sm.Height = 27;
                sm.Text = m.MenuName;
                sm.TextAlign = ContentAlignment.MiddleCenter;
                sm.BackColor = Color.Transparent;
                sm.Top = index * 27 + index * 9 + 9;
                sm.Left = 0;
                sm.Anchor = (System.Windows.Forms.AnchorStyles)(AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right);
                sm.Cursor = Cursors.Hand;
                sm.Tag = m;
                sm.MouseEnter += new EventHandler(sm_MouseEnter);
                sm.MouseLeave += new EventHandler(sm_MouseLeave);
                sm.MouseUp += new MouseEventHandler(sm_MouseUp);
                return sm;
            }
    

    创建子菜单和创建顶部菜单~在原理上是一样的

    也是用的label

    sm.Anchor = (System.Windows.Forms.AnchorStyles)(AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right);

    有了这一句子菜单的宽度会根着Left Panel的宽度的变化而变化

    同时也注册了鼠标的滑入、滑出、弹起事件

    弹起事件就是我们动态创建业务窗体的事件

    我们放到后一节内容介绍

    滑入和滑出的代码如下:

            /// <summary>
            /// 子菜单滑出
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void sm_MouseLeave(object sender, EventArgs e)
            {
                var lb = sender as Label;
                lb.BackColor = Color.Transparent;
            }
            /// <summary>
            /// 子菜单滑入
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void sm_MouseEnter(object sender, EventArgs e)
            {
                var lb = sender as Label;
                lb.BackColor = SystemColors.Info;
            }
    

    再次强烈要求

    喜欢这篇文章或者喜欢我这个人的朋友~点推荐~点推荐~点推荐~点推荐~

     

     

     

     

  • 相关阅读:
    Android API之android.provider.ContactsContract.Data
    Android API之android.provider.ContactsContract
    Android API之android.provider.ContactsContract.Contacts
    Android API之android.os.Parcelable
    Android网络开发之基本介绍
    wpf小技巧——datagrid 滚动条问题
    C# List去重的三种方法(转)
    spring jwt springboot RESTful API认证方式
    Springboot 实现api校验和登录验证
    SpringBoot系列
  • 原文地址:https://www.cnblogs.com/liulun/p/2275097.html
Copyright © 2011-2022 走看看