且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

WinForm企业应用框架设计【三】框架窗体设计;动态创建菜单;

更新时间:2022-08-13 10:25:14

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

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

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

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

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

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

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

另外

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

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

-----------

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

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

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

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

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

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

问题一:关于调试

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

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

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

单步跳入WCF之前会提示

WinForm企业应用框架设计【三】框架窗体设计;动态创建菜单;

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

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

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

我对那段代码做了修改

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

 

好吧!言归正传

一:框架窗体

先看图片 

WinForm企业应用框架设计【三】框架窗体设计;动态创建菜单;

框架窗体分管布局的只有四个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类里

WinForm企业应用框架设计【三】框架窗体设计;动态创建菜单;

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

再次强烈要求

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