从本文开始我们将介绍一个基于MEF的可拓展的WPF程序。这将会是一个比较长的系列性文章,我也不知道会写多长:)。作为系列的第一篇,我们先介绍一下我们到底要做什么吧。我想做过界面的程序员都知道,界面做起来很麻烦,既费时又费力,而且并不一定讨用户喜欢,而且发布起来很麻烦。我想,这也是为什么这些年来网页技术发展得这么红火吧。不知道是不是自己很怀旧,还是实在不习惯总使用浏览器,本人还是很喜欢用desktop application。而且,我们不得不想想,每天除了必要的上网浏览网页,我们其实还是和桌面图形化软件打交道比较多。那么,我们可以不可以搞个比较好用的框架来让我们更好更快的开发desktop application呢?在JAVA领域,我想大部分程序员已经对SWING之流彻底失去信心了,在.NET下,还好我们有WPF。
那么WPF又是什么呢?WPF全名是Windows Presentation Foundation,不知道是不是因为Bill Gates一心投身公益事业,连微软的产品都要加上Foundation。WPF是微软对WinForm的一个全新的发展。WPF的第一个版本是随.NET 3.0发布的,经历了3.5,到现在4.0已经可以说是进入了成熟期了(可以摘掉Beta的名字了,虽然微软本来就没有加上)。相比较其他图形界面API,WPF最大的优势是界面设计和应用逻辑的分离,至少这是微软官方的说法。WPF是一个相对被很多人忽视的东西,这主要是因为在现在互联网的网页时代,有多少人愿意去搞Desktop Application呢?这个问题我不在这里讨论,因为并没有什么讨论的意义。
当我们开始进行WPF编程以后,我们就会发现WPF看似是一个很好用的东西,表面上看,WPF非常友好,MSDN上的很多Example短小精悍,自己模仿起来是很容易的。但是,真个搞起来的时候,我们就会发现,搞好WPF是很难的(当然,什么东西用好都不容易),特别是当我们要做的界面比较复杂的时候,或者说我们要表现的业务逻辑比较复杂的时候。WPF的程序往往开始搞的时候都是很美好的,随着项目的推进,界面的逻辑越来越复杂,程序的质量会直线下降,一直到完全无法维护的程度。那么,WPF到底能不能搞大型项目呢?是不是像WinForm一样一旦做大了就力不从心了呢?
我想微软给了我们很好的答案,那就是Visual Studio 2010,一个基于WPF的大家伙。我相信,我们自己搞的项目不会有Visual Studio那么大,所以我们对WPF是要有信心的。那么,是什么成就了Visual Studio 2010呢?微软告诉我们,是MVVM,这个MVC的发展。我倒是觉得是MEF这个东西。MEF是什么?MEF全名Managed Extensibility Framework,其实就是微软自己的一个拓展架构,像很多人说的那样,一个微软自己的IoC架构。当MEF碰到WPF,就有了我们这一系列文章的正题,那就是可拓展的界面应用程序。
现在看看上面自己写的东西,感觉自己都不知道自己在说什么,舍不得删啊:)这个可拓展的界面应用程序究竟是个什么东西呢?简单来说,就是一个.NET下的像Eclipse一样的东西。Eclipse强大在哪?它是一个界面应用的Host,任何人都可以在上面开发插件,插件的用途可以是千差万别,但是只要你继承了对应的借口,插件就可以在Eclipse里运行。我们在.NET下,就是需要这样的Host。这样,当我们想开发新的东西的时候,就可以直接切入到业务逻辑上,进行插件的开发,没必要考虑很多环境的问题。同时,还可以对以前开发的插件进行代码重用,或者拓展。当然,我是没有本事搞一个像Eclipse那么复杂的东西的,而且我也没有这样的需要。我们真正需要的就是一个简单的可拓展的程序,我们可以把每天零零散散写的程序都变成这个程序的拓展插件,这样可以慢慢积累自己的代码库。要知道,在现在这个编程语言都在拼库的时代,我们自己写的每一行代码都是十分宝贵的,一定不要让他们在硬盘里发霉,要时常拿出来看看。
下面,作为热身,我们做一个简单的关于MEF的小程序。我们先建立一个Console Project,然后添加MEF的Library: System.ComponentModel.Composition.dll.
然后,我们定义一个简单的接口:
public interface Plugin
{
String PluginName { get; set; }
}
然后,我们写一下两个接口的实现:
public class Plugin1 : Plugin
{
public String PluginName { get; set; }
public Plugin1()
{
this.PluginName = "Plugin 1";
}
}
public class Plugin2 : Plugin
{
public String PluginName { get; set; }
public Plugin2()
{
this.PluginName = "Plugin 2";
}
}
下面,我们添加MEF定义。首先我们要加入Using System.ComponentModel.Composition;,当然,如果你有用Resharper的话,请忽略这步,然后:
[Export(typeof(Plugin))]
public class Plugin1 : Plugin
[Export(typeof(Plugin))]
public class Plugin2 : Plugin
在每个Plugin类上添加Attribute。这样就够了,真的够了哦。最后我们需要一个Host程序来初始化MEF:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFConsoleExample
{
class Program
{
[ImportMany(typeof(Plugin))]
public Plugin[] Plugins;
public Program()
{
var result = this.Compose();
if (result == false)
{
return;
}
else
{
foreach (var plugin in Plugins)
{
Console.WriteLine("Plugin name: " + plugin.PluginName);
}
}
}
static void Main(string[] args)
{
var test = new Program();
}
private bool Compose()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var provider = new ComposablePartExportProvider();
var container = new CompositionContainer(catalog, provider);
provider.SourceProvider = container;
var batch = new CompositionBatch();
batch.AddPart(this);
try
{
container.Compose(batch);
}
catch (CompositionException exception)
{
Console.WriteLine(exception.ToString());
return false;
}
return true;
}
}
}
就这么简单,运行程序我们会看到:
Plugin name: Plugin 1
Plugin name: Plugin 2
Press any key to continue . . .
当然,上面的这些只是皮毛中的皮毛,不过今天不想写了,以后再慢慢写吧。