Management Studio是我在WinForms小项目开发过程中搭建起来的一个插件式结构的应用程序框架,因为简单灵活又容易扩展,现在将它开源供读者参考。
跑起来的效果图如下所示,具备选项卡式多文档界面,Office 2007蓝色风格,插件式结构等特性。
选项卡式多文档界面 Tab MDI
通过Infragistics Dock控件,可以很容易的实现选项卡式多文档界面。只需要在主界面的窗体设计器组件栏中拖入一个ultraTabbedMdiManager控件,设定主窗体的IsMdiContainer属性为true,剩下的工作就交由这个组件来负责。
当我们用下面的代码创建一个子窗体时,它会自动的产生一个选项卡文档,参考下面代码。
Startup frm = new Startup();
frm.MdiParent = this;
frm.Show();
从上面的代码片段中可以看到仍旧是MDI的编程风格,但产生的结果是选项卡式的界面。
插件结构 PlugIn
借助于反射机制,读取当前程序集中的类型定义,找到包含有指定特性的类型,创建它的实例,即可实现基本的插件式结构。
首先,我们给需要的窗体类增加FunctionCode特性,参考下面的代码。
[FunctionCode("DataSetReader")]
public partial class DataSetReader : FormBase
{
public DataSetReader()
{
InitializeComponent();
}
然后修改创建窗体的代码,从当前的程序集类型中搜索,找到指定特性的窗体的类型后,创建它的实例。关键的代码如下面所示。
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
try
{
object[] attributes = type.GetCustomAttributes(typeof(FunctionCode), true);
foreach (object obj in attributes)
{
FunctionCode attribute = (FunctionCode)obj;
if (!string.IsNullOrEmpty(attribute.Value))
{
if (!_formBaseType.ContainsKey(attribute.Value))
_formBaseType.Add(attribute.Value, type);
if (formBaseType == null && attribute.Value.Equals(functionCode,StringComparison.InvariantCultureIgnoreCase))
formBaseType = type;
}
最后,我们添加一个菜单项,用于显示当前已经存在的功能编码给用户选择,菜单项的实现用XML文件定义,参考项目中嵌入的资源文件ListItem.xml。
<?xml version="1.0" encoding="utf-8" ?>
<Items>
<Item Index="0" Text="DataSet Reader" Tag="DataSetReader" ImageIndex="17"></Item>
<Item Index="1" Text="Translation" Tag="Translation" ImageIndex="32"></Item>
<Item Index="2" Text="String Builder" Tag="TextToStringBuilder" ImageIndex="33"></Item>
<Item Index="3" Text="License Generator" Tag="GenLicense" ImageIndex="7"></Item>
<Item Index="4" Text="Query Generator" Tag="QueryGenerator" ImageIndex="34"></Item>
<Item Index="5" Text="Lookup Generator" Tag="LookupGenerator" ImageIndex="35"></Item>
<Item Index="6" Text="Report Generator" Tag="ReportGenerator" ImageIndex="36"></Item>
<Item Index="7" Text="Query Lookup" Tag="QueueLookUpForm" ImageIndex="37"></Item>
<Item Index="8" Text="Database Update" Tag="DatabaseUpdate" ImageIndex="38"></Item>
</Items>
运行时读取嵌入的资源项,生成如下界面所示的列表视图。
双击列表视图中的项或选择项后点OK都可以打开指定的功能对应的窗体。
Office 2007 蓝色风格 Office Render
借用CodeProject上的一篇文章提供的组件,我们只需要在主界面的OnLoad方法中增加2行代码即可实现蓝色的界面风格。
private void Form1_Load(object sender, EventArgs e)
{
ToolStripManager.Renderer = new ERP.Misc.Office2007Renderer();
statusStrip.Renderer = new ERP.Misc.Office2007Renderer();
Office Render组件已经设置好了默认的颜色风格,并不需要我们去调整。程序员大多没有色彩知识,ASP.NET 组件Ext.NET也是一个蓝色风格的组件,它内置的蓝色风格很受欢迎,程序员不喜欢也没有能力去维护这个复杂的配色方案,只想拿来用就可以了。
private static Color _c1 = Color.FromArgb(167, 167, 167);
private static Color _c2 = Color.FromArgb(21, 66, 139);
private static Color _c3 = Color.FromArgb(76, 83, 92);
private static Color _c4 = Color.FromArgb(250, 250, 250);
private static Color _c5 = Color.FromArgb(248, 248, 248);
private static Color _c6 = Color.FromArgb(243, 243, 243);
private static Color _r1 = Color.FromArgb(255, 255, 251);
private static Color _r2 = Color.FromArgb(255, 249, 227);
private static Color _r3 = Color.FromArgb(255, 242, 201);
private static Color _r4 = Color.FromArgb(255, 248, 181);
后台线程 WorkerThreadBase
WorkerThreadBase也是CodeProject上面的一篇文章的代码。通常与界面相关的长时间的操作我们应该用BackgroundWorker组件封装起来以避免界面死锁。如果不是与界面相关的操作,我们可以用多线程,并行等方法实现,也可以用这里提到的WorkerThreadBase,它的例子代码如下所示,下面是一个复制文件的例子。
public class CopyFileWorker : WorkerThreadBase
{
private static CopyInfo _copyInfo;
public CopyFileWorker(CopyInfo copyInfo)
{
_copyInfo = copyInfo;
}
protected override void Work()
{
copyFiles(_copyInfo);
}
private void copyFiles(CopyInfo copyInfo)
{
//check if the user called Stop
if (StopRequested)
{
Console.WriteLine("User called Stop.");
Console.WriteLine("Terminating thread while copying directory '{0}'.", copyInfo.Source);
return;
}
if (!Directory.Exists(copyInfo.Destination))
{
Directory.CreateDirectory(copyInfo.Destination);
}
Console.WriteLine("CopyFiles from '{0}' to '{1}' {2}...", copyInfo.Source,copyInfo.Destination, copyInfo.Recursive ? "recursive" : "non-recursive");
foreach (string file in Directory.GetFiles(copyInfo.Source))
{
string destination = Path.Combine(copyInfo.Destination,Path.GetFileName(file));
File.Copy(file, destination);
}
if (copyInfo.Recursive)
{
foreach (string directory in Directory.GetDirectories(copyInfo.Source))
{
string destination = Path.Combine(copyInfo.Destination,Path.GetFileName(directory)); //get the directory name for the path
copyFiles(new CopyInfo(directory,destination,copyInfo.Recursive));
}
}
Console.WriteLine("CopyFiles finished.");
}
继承于WorkerThreadBase,将要操作的方法放到Work方法中重写,启动一个或多个后台线程任务的例子代码参考下面的程序片段。
DummyWorker dummyWorker = new DummyWorker();
dummyWorker.Start();
CopyFileWorker copyFileWorker = new CopyFileWorker(_copyInfo);
copyFileWorker.Start();
//wait for the two threads to finish
WorkerThreadBase.WaitAll(copyFileWorker, dummyWorker);
文本转化为.NET字符串
Management Studio的源代码包中提供几个基础的功能,比如这里的将字符串转化为.NET代码的功能。这个功能的源代码来自网友的代码,当时觉得很有用一直收藏着。
曾经有一段时间发现.NET的字符串前缀转义标识@支持换行,参考下面的代码例子,@符号支持多行文本。
private string test = @" [assembly: AssemblyCopyright(Copyright © 2015)]
[assembly: AssemblyTrademark()]
[assembly: AssemblyCulture()]";
中文繁体简体转换
使用Microsoft.VisualBasic程序集中的方法,一步代码调用实现简体转化为繁体,参考下面的方法代码。
public string Convert(string s)
{
return (Microsoft.VisualBasic.Strings.StrConv(s as string, Microsoft.VisualBasic.VbStrConv.TraditionalChinese, 0));
}
异常处理
凡是WinForms程序,应该在你的程度开头增加下面的几行代码以实现异常处理,将系统抛出的异常转化给当前程序处理,并提供友好的界面显示异常。
CustomExceptionHandler eh = new CustomExceptionHandler();
Application.ThreadException += new ThreadExceptionEventHandler(eh.OnThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Management Studio源代码下载:http://files.cnblogs.com/files/JamesLi2015/ManagementStudio.zip