自发布《多文档界面(MDI)系统框架-C#完整版》后又有了新想法,就是再写个C#版C/S结构系统框架。
因时间关系断断续续写了很久。借周日机会,我将源代码整理好再写些说明文档发布出来,希望给大家
带来学习机会。
特别声明的是: C/S结构系统框架是优化和改编自几个大型系统,是经历过考验和实际应用的。希望大家好好珍惜。这个框架有很多学习要点,提醒大家不仅仅是下载代码而应该去好好研究,甚至阅读每一行代码每一个模块每一个细节! 你学会了它也许将来作为一个优秀架构师需要设计同样一个系统时,这时你用上它,不是事半功倍么?
另外,请尊重作者版权,写一个框架的确需要大量时间和精力。程序员有个共性是写作永无止境,虽是深夜2点,但我们仍在思考,仍在写作! 眼睛睡觉了但思维和创作动力仍在冗奋中,作为一个程序员的你,我说的对吗?有同样的感受吗? 所以:转载时请注明本文来自易学网www.vjsdn.net!
言归正传,接下来讲解系统框架实现过程。
首先看几个图对框架有个初步认识。
1.登陆窗体
准备登录窗体
如通过验证用户,则加载MDI主窗体,留意图片内的动态消息:
正在初始化用户界面,请稍候.
登录窗体是多数应用程序的入口,在进入系统前需要用户验证。请看实现过程:
2.MDI主窗体
登录成功后显示MDI主窗体.
图片为测试模块II的主界面.
登录成功后显示MDI主窗体.
图片为系统管理模块的主界面.
3.关于程序/作者
4.解决方案
用代码实现登录到加载MDI主窗体.
1.程序入口代码:
static class Program
{
[STAThread]
static void Main()
{
// 捕获系统所产生的异常。
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
SystemConfig.ReadSettings(); // 读取系统设置
bllService.SetDataBasePath(); // 因用到Access,指定一个MDB文件
Process instance = SingletonProgram.GetRunningInstance();
if (instance != null ) Msg.Warning( " 程序已经运行. " );
if ((instance != null ) && ( ! SystemConfig.CurrentConfig.AllowRunMultiInstance))
{
SingletonProgram.HandleRunningInstance(instance); // Active instance
return ;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
// 注意:先打开登陆窗体,如登陆成功后再正式运行程序(MDI 主窗体)
// 学会这种写法。
if (AppEntry.Login())
Application.Run(AppEntry.MainForm);
else
Application.Exit();
}
private static void Application_ThreadException( object sender, ThreadExceptionEventArgs e)
{
Msg.ShowException(e.Exception);
}
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
留意这段代码:
if (AppEntry.Login())
Application.Run(AppEntry.MainForm);
else
Application.Exit();
调用AppEntry类表态方法Login(),如登录成功,此时已经创建MainForm实例,则运行主窗体.
AppEntry类是个公共类,仅定义登录方法及MDI主窗体变量.
在登录窗体内用到该类.用户登录成功则创建frmMain实例.然后调用Application.Run(AppEntry.MainForm)方法.
2.AppEntry类,应用程序入口类.
public class AppEntry
{
public static bool Login()
{
return frmLogin.TryLogin();
}
private static frmMain _mainForm = null ;
public static frmMain MainForm { get { return _mainForm; } set { _mainForm = value; } }
}
3.登录窗体源代码:
public partial class frmLogin : Form
{
// 将构造器设为静态,防止外部创建实例
private frmLogin()
{
InitializeComponent();
}
/// <summary>
/// 打开登陆窗体,公开一个主静态方法
/// </summary>
/// <returns></returns>
public static bool TryLogin()
{
frmLogin form = new frmLogin();
bool ret = form.ShowDialog() == DialogResult.OK;
return ret;
}
private void btnLogin_Click( object sender, EventArgs e)
{
// 调用业务层登录方法
bool ret = new bllUser().Login(txtUser.Text, txtPwd.Text);
if (ret)
{
// 登录成功创建主窗体
AppEntry.MainForm = new frmMain();
// 初始化主窗体(如加载模块,初始化用户界,加载系统参数)
// 在初始化同时login窗体会动态显示信息。
AppEntry.MainForm.InitUserInterface( new StatusLable( this .lblLoadingInfo));
this .DialogResult = DialogResult.OK;
this .Close(); // 关闭登陆窗体
}
else
{
Msg.Warning( " 登录失败,请检查用户名和密码! " );
}
}
private void btnCancel_Click( object sender, EventArgs e)
{
this .Close();
}
}
转载请注明来自易学网 http: // www.vjsdn.net/ 易学原创作品
这里需要调用业务层执行用户登录. 要学会将业务代码与界面代码分离.
// 调用业务层登录方法
bool ret = new bllUser().Login(txtUser.Text, txtPwd.Text);
if (ret)
{
.........
当登录成功,创建MDI主窗体实例,然后调用实例方法InitUserInterface.这时初始化主窗体.
// 初始化主窗体(如加载模块,初始化用户界,加载系统参数)
// 在初始化同时login窗体会动态显示信息。
AppEntry.MainForm.InitUserInterface( new StatusLable( this .lblLoadingInfo));
4.下面是MDI主窗体的代码:
public partial class frmMain : Form
{
// 模块管理器实例
private ModuleManager _ModuleManager;
public frmMain()
{
InitializeComponent();
}
// 初始化用户接口
public void InitUserInterface(StatusLable splash)
{
this .SuspendLayout();
splash.UpdateMessage( " 正在初始化用户界面,请稍候... " );
_ModuleManager = new ModuleManager( this , xtraTabControl1); // 创建模块管理器
_ModuleManager.LoadModules(splash); // 加载可用模块
splash.UpdateMessage( " 正在加载工具栏... " );
_ModuleManager.CreateNavBarButtons( this .navBarControl1, this .menuStrip1); // 创建导航工具栏按钮
splash.UpdateMessage( " 正在加载用户模块... " );
splash.UpdateMessage( " 正在初始化数据... " );
splash.UpdateMessage( " 加载完毕. " );
this .ResumeLayout();
}
/// <summary>
/// 显示由参数指定的模块
/// </summary>
public void ActiveModule( string moduleDisplayName)
{
foreach (XtraTabPage page in this .xtraTabControl1.TabPages)
{
if (page.Text.Equals(moduleDisplayName))
{
xtraTabControl1.SelectedTabPage = page;
return ;
}
}
}
private void btnHelp_Click( object sender, EventArgs e)
{
new frmAboutVjsdn().ShowDialog();
}
private void btnClose_Click( object sender, EventArgs e)
{
this .Close();
}
private void btnAbout_Click( object sender, EventArgs e)
{
new frmAboutVjsdn().ShowDialog();
}
}
转载请注明来自易学网 http: // www.vjsdn.net/ 易学原创作品
窗体类定义一个_ModuleManager变量,用于加载模块.请看ModuleManager详解.
InitUserInterface()方法是初始化主窗体方法.由frmLogin调用.
转载请注明来自易学网 http://www.vjsdn.net/ 易学原创作品
C# C/S结构数据库系统框架详解(二) ModuleManager详解[vjsdn]
一个大的应用程序由大量模块构成, 因人而异模块的理解和分类各有不同. 在C/S框架内我将模块(Module)定义为一个DLL程序(Class Library). 而每个DLL程序按业务分类. 如进销存系统我们可定义3个模块:采购模块(Purchase Module),销售模块(Sales Module)和库存模块(Inventory Module).而每个模块的业务代码封装在
DLL Class Library内. 则构成3个独立的DLL和一个可执行EXE文件. 如要细分还有公共模块(Common Module), 数据访问层(Data Access Layer Module),系统安全(System Security Module)和系统设置模块(System Setups Module)等模块. 这样就构成一个简单的多模块系统框架了.
C/S框架内定义了8个模块(DLL)和一个主程序(EXE).
从设计角度上讲模块也要分类,可分为系统模块和业务模块.
系统模块是框架组成部分,如Business.dll,Common.dll,DataAccess.dll,Library.dll,Models.dll.
业务模块封装核心业务,包括业务窗体,图片资源等信息. 如上所述的进销存系统:进,销,存3个模块为业务模块.
我们对模块有了初步认识. 由此可见一个系统是由很多模块构成的,而系统越大分的模块越多,模块越多程序越复杂和难以控制.当然安全问题也应运而生了.
假设A用户仅能使用采购模块(Purchase Module),另两个模块不可见, 在设计上我们可以这么做:
1.设计权限,隐藏其它两个模块.
2.在客户机仅发布exe和purchase.dll
3.其它设计.
假设不按业务独立模块,我想设计权限来隐藏其它两个模块是件复杂而危险的事. 可想而知你需要在每个窗体每个业务类都要判断A用户是否有Sales和Inventory的权限,成百上千种判断会使你疯狂!
但是只给客户机安装一个purchase.dll,即使在设计上不判断权限也用不着Sales和Inventory任何功能!
假设我们选择第2种方法, 因客户不同发布的dll也不同,这里牵涉到动态加载dll的问题!本文的重点就是介绍如何动态加载模块.下面且看相关源代码:
ModuleID类:模块编号,给每个模块一个唯一编号.
/// <summary>
/// 模块编号,给每个模块一个唯一编号.
/// </summary>
public enum ModuleID
{
None = 0 ,
TestModule1 = 1 , // 测试模块1
TestModule2 = 2 , // 测试模块2
SystemManage = 3 , // 系统管理模块
}
模块信息类:实体类,封装与模块相关信息.
/// <summary>
/// 模块信息类
/// </summary>
public class ModuleInfo
{
private Assembly _ModuleAssembly = null ;
private ModuleID _ModuleID = ModuleID.None;
private string _ModuleName = string .Empty;
private string _ModuleFile = string .Empty;
/// <summary>
/// 构造器
/// </summary>
public ModuleInfo(Assembly asm, ModuleID id, string name, string file)
{
_ModuleAssembly = asm;
_ModuleFile = file;
_ModuleID = id;
_ModuleName = name;
}
/// <summary>
/// 加载DLL文件后程序集指针
/// </summary>
public Assembly ModuleAssembly
{
get { return _ModuleAssembly; }
set { _ModuleAssembly = value; }
}
/// <summary>
/// 模块文件(*.dll)
/// </summary>
public string ModuleFile
{
get { return _ModuleFile; }
set { _ModuleFile = value; }
}
/// <summary>
/// 模块名称
/// </summary>
public string ModuleName
{
get { return _ModuleName; }
set { _ModuleName = value; }
}
/// <summary>
/// 模块编号
/// </summary>
public ModuleID ModuleID
{
get { return _ModuleID; }
set { _ModuleID = value; }
}
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
ModuleLoader:模块加载器. 通过ModuleLoader类动态加载模块dll, 将程序集Assembly保存在
_ModuleAssembly变量.
/// <summary>
/// 模块加载器
/// </summary>
public class ModuleLoader
{
private string _ModuleFileName; // DLL 文件名
private frmModuleBase _ModuleMainForm; // 如果加載了模塊. 返回該模塊的主窗體對象.
private Assembly _ModuleAssembly;
public static readonly string MODULE_FILTER = " 易学网C/S系统框架模块|VJSDN C/S Modules|*.dll " ;
public static readonly string MODULE_PATH = Application.StartupPath;
public ModuleLoader()
{
//
}
/// <summary>
/// 模块所在的程序集
/// </summary>
public Assembly ModuleAssembly
{
get { return _ModuleAssembly; }
}
/// <summary>
/// 返回AssemblyModuleEntry,自定义模块特性
/// </summary>
public string GetCurrentModuleName()
{
return ModuleLoader.GetModuleEntry(_ModuleAssembly).ModuleName;
}
/// <summary>
/// 模块主窗体
/// </summary>
public frmModuleBase ModuleMainForm
{
get { return _ModuleMainForm; }
}
/// <summary>
/// 加载模块的菜单
/// </summary>
/// <param name="menuStrip"> 程序主窗体的菜单 </param>
public void LoadMenu(MenuStrip menuStrip)
{
if (_ModuleMainForm != null && _ModuleMainForm.GetModuleMenu() != null )
{
menuStrip.Items.Insert(menuStrip.Items.Count - 1 , _ModuleMainForm.GetModuleMenu().Items[ 0 ]);
}
}
/// <summary>
/// 加载模块主方法
/// </summary>
/// <param name="moduleinfo"> 模块信息 </param>
/// <returns></returns>
public bool LoadModule(ModuleInfo moduleinfo)
{
_ModuleFileName = moduleinfo.ModuleFile;
_ModuleAssembly = moduleinfo.ModuleAssembly;
string entry = GetModuleEntryNameSpace(_ModuleAssembly);
if ( string .Empty == entry) return false ;
Form form = (Form)_ModuleAssembly.CreateInstance(entry);
_ModuleMainForm = null ;
if (form is IModuleBase)
_ModuleMainForm = (frmModuleBase)form;
return _ModuleMainForm != null ;
}
/// <summary>
/// 获取模块列表,转换为ModuleInfo集合.
/// </summary>
public IList < ModuleInfo > GetModuleList()
{
try
{
string [] files = null ; // 模塊文件(*.dll)
IList < ModuleInfo > list = new List < ModuleInfo > ();
if (Directory.Exists(MODULE_PATH))
files = Directory.GetFiles(MODULE_PATH, " *.dll " );
foreach ( string mod in files)
{
Assembly asm = null ;
try
{
// .net framework dll
asm = Assembly.LoadFile(mod);
}
catch { continue ; }
ModuleID id = GetModuleID(asm);
string name = GetCurrentModuleName();
if (id != ModuleID.None)
{
ModuleInfo m = new ModuleInfo(asm, id, name, mod);
list.Add(m);
}
}
SortModule(list); // 模塊排序.
return list;
}
catch (Exception ex)
{
Msg.ShowException(ex);
return null ;
}
}
/// <summary>
/// 获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
/// </summary>
/// <returns></returns>
public AssemblyModuleEntry GetModuleEntry()
{
return ModuleLoader.GetModuleEntry(_ModuleAssembly);
}
/// <summary>
/// 判断加载的文件是否模块文件,因目录下可能有不同类别的DLL文件。
/// 判断DLL为模块的条件是检查Assembly特性。
/// </summary>
public bool IsModuleFile( string moduleFile)
{
try
{
Assembly asm = Assembly.LoadFile(moduleFile);
return (ModuleLoader.GetModuleID(asm) != ModuleID.None);
}
catch { return false ; }
}
/// <summary>
/// 每一个模块对应一个XtraTabPage,然后將模块主窗体的Panel容器放置在XtraTabPage内。
/// 因此,所有加载的模块主窗体的Panel容器都嵌套在主窗体的XtraTabControl内。
/// </summary>
public void LoadGUI(XtraTabControl mainTabControl)
{
try
{
IModuleBase moduleBase = _ModuleMainForm as IModuleBase;
Panel container = moduleBase.GetContainer(); // 模块主窗体的Panel容器
if ( null != container)
{
container.Dock = DockStyle.Fill;
XtraTabPage page = new XtraTabPage();
page.Text = this .GetCurrentModuleName();
page.Controls.Add(container);
mainTabControl.TabPages.Add(page);
}
}
catch (Exception ex) { Msg.ShowException(ex); }
}
/// <summary>
/// 模块排序
/// </summary>
/// <param name="list"></param>
public void SortModule(IList < ModuleInfo > list)
{
int i, j;
ModuleInfo temp;
bool done = false ;
j = 1 ;
while ((j < list.Count) && ( ! done))
{
done = true ;
for (i = 0 ; i < list.Count - j; i ++ )
{
if ((list[i] as ModuleInfo).ModuleID > (list[i + 1 ] as ModuleInfo).ModuleID)
{
done = false ;
temp = list[i];
list[i] = list[i + 1 ];
list[i + 1 ] = temp;
}
}
}
}
#region 类公共表态方法
/// <summary>
/// 查找子菜单,深度搜索
/// </summary>
public static ToolStripMenuItem GetMenuItem(ToolStrip mainMenu, string menuName)
{
ToolStripItem[] items = mainMenu.Items.Find(menuName, true );
if (items.Length > 0 && items[ 0 ] is ToolStripMenuItem)
return (ToolStripMenuItem)items[ 0 ];
else
return null ;
}
/// <summary>
/// 获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
/// </summary>
public static AssemblyModuleEntry GetModuleEntry(Assembly asm)
{
AssemblyModuleEntry temp = new AssemblyModuleEntry(ModuleID.None, "" , "" );
if (asm == null ) return temp;
object [] list = asm.GetCustomAttributes( typeof (AssemblyModuleEntry), false );
if (list.Length > 0 )
return (AssemblyModuleEntry)list[ 0 ];
else
return temp;
}
/// <summary>
/// 获取模块主窗体名字空间
/// </summary>
public static string GetModuleEntryNameSpace(Assembly asm)
{
return GetModuleEntry(asm).ModuleEntryNameSpace;
}
/// <summary>
/// 獲取模塊編號
/// </summary>
public static ModuleID GetModuleID(Assembly asm)
{
return ModuleLoader.GetModuleEntry(asm).ModuleID;
}
#endregion
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
模块控制类
1.管理ModuleLoader加载的模块.
2.动态创建菜单及导航条按钮.
3.将所有模块主窗体组合在XtraTabControl 控件内. 每个XtraTabPage对应一个模块.
/// <summary>
/// 模块管理器
/// </summary>
public class ModuleManager
{
// 程序主窗体的TabControl,用于放置模块主窗体
private XtraTabControl _tabControlModules = null ;
// 程序主窗体
private Form _MDIMainForm = null ;
private static IList < ModuleInfo > _Modules = null ;
/// <summary>
/// 获取回载的模块
/// </summary>
public static IList < ModuleInfo > GetAvailableModules()
{
return _Modules;
}
/// <summary>
/// 构造器
/// </summary>
public ModuleManager(Form mdiMainForm, XtraTabControl tabControlModules)
{
_tabControlModules = tabControlModules;
_MDIMainForm = mdiMainForm;
}
/// <summary>
/// Navigator bar 导航条按鈕事件.
/// </summary>
public static void OnNavBarLinkClick( object sender, NavBarLinkEventArgs e)
{
if (e.Link.Item.Tag is ToolStripItem)
{
ToolStripItem item = (ToolStripItem)(e.Link.Item.Tag);
if ( null != item) item.PerformClick(); // 執行菜單事件.
}
}
/// <summary>
/// 是否有子菜單.
/// </summary>
private bool IsSubMenuOwner(ToolStripItem item)
{
if (item is ToolStripMenuItem)
{
if (((ToolStripMenuItem)item).DropDownItems.Count > 0 )
return true ;
}
return false ;
}
/// <summary>
/// 由菜单创建导航条控件按钮
/// </summary>
private NavBarItem CreateNavBarItem(NavBarControl navBar, ToolStripItem item)
{
NavBarItem newItem = new NavBarItem();
newItem.Caption = item.Text;
newItem.Tag = item; // 綁定一個菜單項,newItem.Click事件會使用這個菜單項
newItem.LinkClicked += new NavBarLinkEventHandler(ModuleManager.OnNavBarLinkClick);
navBar.Items.Add(newItem);
return newItem;
}
/// <summary>
/// 导航条控件按钮分组
/// </summary>
private NavBarGroup CreateNavBarGroup(NavBarControl navBar, string caption)
{
NavBarGroup group = navBar.Groups.Add(); // 增加一個Button組.
group.Caption = caption; // 模塊的顯示名稱
group.LargeImageIndex = 0 ;
if (group.Caption.Equals( string .Empty)) group.Caption = " Unknown Name " ;
return group;
}
/// <summary>
/// 当点击导航条分组按钮时触发该事件
/// </summary>
private void OnActiveGroupChanged( object sender, DevExpress.XtraNavBar.NavBarGroupEventArgs e)
{
try
{
string moduleName = e.Group.Caption.ToString();
this .ActiveModule(moduleName);
}
catch (Exception ex) { Msg.ShowException(ex); }
}
/// <summary>
/// 显示指定的模块主窗体
/// </summary>
public void ActiveModule( string moduleDisplayName)
{
foreach (XtraTabPage page in this ._tabControlModules.TabPages)
{
if (page.Text.Equals(moduleDisplayName))
{
_tabControlModules.SelectedTabPage = page;
return ;
}
}
}
/// <summary>
/// 创建导航条分组按钮 Navigator NavBarGroup
/// </summary>
/// <param name="navBar"> NavBarControl对象 </param>
/// <param name="moduleMenu"> 模块主菜单 </param>
/// <param name="moduleDisplayName"> 模块名称 </param>
public NavBarGroup CreateNavBarButton(NavBarControl navBar, ToolStripMenuItem moduleMenu, string moduleDisplayName)
{
navBar.ActiveGroupChanged += new NavBarGroupEventHandler(OnActiveGroupChanged);
NavBarGroup group = CreateNavBarGroup(navBar, moduleDisplayName); // 根据模块名称创建Group
if (moduleMenu == null ) return group; // 组没有菜单则返回,实为一个空组无子按钮.
foreach (ToolStripItem menuItem in moduleMenu.DropDownItems)
{
if (menuItem is ToolStripSeparator) continue ;
if (IsSubMenuOwner(menuItem)) continue ;
if (menuItem.Enabled)
{
NavBarItem item = CreateNavBarItem(navBar, menuItem);
item.SmallImageIndex = 1 ; // Sub Function
group.ItemLinks.Add(item);
}
}
return group;
}
/// <summary>
/// 初始化NavBar控件.绑定组NavGroup.ActiveGroupChanged事件
/// </summary>
public void CreateNavBarButtons(NavBarControl navBar, MenuStrip mainMenu)
{
try
{
navBar.SuspendLayout();
navBar.Items.Clear();
navBar.Groups.Clear();
foreach (XtraTabPage page in this ._tabControlModules.TabPages)
{
// 取主窗体对应的顶级菜单
ToolStripMenuItem moduleMenu = FindMenuItemByText(mainMenu, page.Text);
if (moduleMenu != null && moduleMenu.Enabled) // 创建该模块的NavBarButton.
this .CreateNavBarButton(navBar, moduleMenu, page.Text);
}
navBar.ResumeLayout();
}
catch (Exception ex) { Msg.ShowException(ex); }
}
private ToolStripMenuItem FindMenuItemByText(MenuStrip mainMenu, string text)
{
foreach (ToolStripMenuItem item in mainMenu.Items)
if (item.Text == text) return (ToolStripMenuItem)item;
return null ;
}
/// <summary>
/// 加载模块主方法
/// </summary>
public void LoadModules(StatusLable msg)
{
try
{
ModuleLoader loader = new ModuleLoader();
_Modules = loader.GetModuleList(); // 從目錄裝載模塊
foreach (ModuleInfo m in _Modules) // 枚舉文件名列表.
{
if ( ! loader.LoadModule(m)) continue ;
msg.UpdateMessage( " 正在加载: " + loader.GetCurrentModuleName());
loader.LoadGUI(_tabControlModules);
loader.LoadMenu(_MDIMainForm.MainMenuStrip);
loader.ModuleMainForm.MdiParent = _MDIMainForm; // 设置模块主窗体的父窗体.
}
GC.Collect();
}
catch (Exception ex) { Msg.ShowException(ex); }
}
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
为了规范模块共有的特性,设计一个模块主窗体接口.
/// <summary>
/// 模块主窗体接口
/// </summary>
public interface IModuleBase
{
ModuleID GetModuleID(); // 获取模块编号
ModuleInfo GetModuleInfo(); //
Panel GetContainer(); // 模块主窗体容器
MenuStrip GetModuleMenu();
void InitButton();
void InitMenu();
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
定义一个模块主窗体基类来实现这个接口.
/// <summary>
/// 模块主窗体基类
/// </summary>
public partial class frmModuleBase : frmBase, IModuleBase
{
public frmModuleBase()
{
InitializeComponent();
}
#region IModuleBase Members
// 模块的主菜单
public virtual MenuStrip GetModuleMenu()
{
return null ;
}
// 模块编号
public virtual ModuleID GetModuleID()
{
return ModuleID.None;
}
// 模块信息
public virtual ModuleInfo GetModuleInfo()
{
return null ;
}
// 模块主窗体容器
public virtual Panel GetContainer()
{
return this .pnlContainer;
}
// 初始化按钮
public virtual void InitButton()
{
}
// 初始化菜单
public virtual void InitMenu()
{
}
#endregion
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品
C# C/S结构数据库系统框架详解(三) 如何新建一个模块(InventoryModule)[vjsdn]
1. 新增一个Class Library项目,命名为vjsdn.CS3Layers_Framework.InventoryModule.
2. 在项目内新增一个Inherited Form,命名为frmModuleMain,按Add按钮,选择frmModuleBase基类.
3. 在ModuleID枚举新增一个枚举类型,命名为InventoryModule=4.
/// <summary>
/// 模块编号
/// </summary>
public enum ModuleID
{
None = 0 ,
TestModule1 = 1 ,
TestModule2 = 2 ,
SystemManage = 3 ,
InventoryModule = 4 // 库存模块
}
4. 展开项目的Properties结点,打开AssemblyInfo.cs文件, 加入下面代码:
[assembly: AssemblyModuleEntry(ModuleID.InventoryModule, " 库存模块 " , " vjsdn.CS3Layers_Framework.InventoryModule.frmModuleMain " )]
这步非常重要,需要指定ModuleID,模块名称和模块主窗体的名字空间. 模块名称需要与模块主窗体菜单的名字一致!请看第8步菜单名称.
5.在frmModuleMain窗体内加入一个menuStrip控件,修改一级菜单的Text属性为库存模块.另加两个子菜单为库存查询和库存盘点.
6.在frmModuleMain窗体pnlContainer控件内加两上按钮命名为btnQuery,btnChecking.分别在Click事件内
输入
MessageBox.Show((sender as Button).Text);
7.子菜单[库存查询]的Click事件设为btnQuery_Click
8.子菜单[库存盘点]的Click事件设为btnChecking_Click, 下图是窗体设计状态
9.重写GetModuleMenu方法
public override MenuStrip GetModuleMenu()
{
menuStrip1.Text = " 库存模块 " ; // 与AssemblyModuleEntry.ModuleName定义相同
return this .menuStrip1;
}
设计后的代码:
namespace vjsdn.CS3Layers_Framework.InventoryModule
{
// 库存模块主窗体
public partial class frmModuleMain : vjsdn.CS3Layers_Framework.Library.frmModuleBase
{
public frmModuleMain()
{
InitializeComponent();
}
public override MenuStrip GetModuleMenu()
{
menuStrip1.Text = " 库存模块 " ; // 与AssemblyModuleEntry.ModuleName定义相同
return this .menuStrip1;
}
private void btnChecking_Click( object sender, EventArgs e)
{
MessageBox.Show((sender as Button).Text);
}
private void btnQuery_Click( object sender, EventArgs e)
{
MessageBox.Show((sender as Button).Text);
}
}
}
10.设置项目的output path为: ../Debug/, 所有编译的程序放在同一目录.
编译后运行:
图中有四个业务模块,库存模块是新增的.
全部链接:
1.C/S结构数据库系统框架详解
http://www.vjsdn.com/bbs/bbsTopicDetails.aspx?pid=109201218
2.ModuleManager详解
http://www.vjsdn.com/bbs/bbsTopicDetails.aspx?pid=109201219
3.如何新建一个模块
http://www.vjsdn.com/bbs/bbsTopicDetails.aspx?pid=109201220
4.C/S结构数据库系统框架源代码
http://www.vjsdn.com/bbs/bbsTopicDetails.aspx?pid=109201221