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; }
再次强烈要求
喜欢这篇文章或者喜欢我这个人的朋友~点推荐~点推荐~点推荐~点推荐~