這兩天看到同事的一個小工具,用的是模塊式開發,也就是俗稱的插件開發,用的是反射+接口的方式實現的。感覺挺好的,也就學習了一下,寫個小Demo,在此記錄下。
一、寫接口類
接口類是所有模塊的基礎,因為讓主程序去尋找模塊,就是通過反射來找到繼承此接口的相關項目,也就是後期包含繼承此接口類的DLL文件。
此接口類包含以下幾個屬性
工具的名稱(必需)、是否要彈出、前景色、背景色、工具啟動方法(必需)
public interface IToolsInterface
{
/// <summary>
/// 獲取工具名稱
/// </summary>
string ToolName
{
get;
}
/// <summary>
/// 是否彈出
/// </summary>
bool IsPopUp
{
get;
}
/// <summary>
/// 前景色
/// </summary>
Brush ForgroundBrush
{
get;
}
/// <summary>
/// 背景色
/// </summary>
Brush BackgroundBrush
{
get;
}
/// <summary>
/// 工具啟動方法
/// </summary>
/// <returns></returns>
FrameworkElement RunToolApplication();
}
二、寫主窗體
所謂的主窗體,也就是各個模塊的承載器而已,因為各個模塊都是UserControl,需要窗體來承載。
需要的方法大概有兩個,尋找目錄的層級、創建相應的模塊。
1、尋找目錄層級
因為模塊最終要生成到一個位置,然後讓主程序去搜索,所以,需要一個搜索方法,去尋找
/// <summary>
/// 查找指定目錄下的所有末級子目錄
/// </summary>
/// <param name="dir">要查找的目錄</param>
/// <param name="dirList">查找結果列表</param>
/// <param name="system">是否包含系統目錄</param>
/// <param name="hidden">是否包含隱藏目錄</param>
public static void GetEndDirectories(DirectoryInfo dir,List<DirectoryInfo> dirList,bool system=false,bool hidden=false)
{
try
{
//返回當前目錄的子目錄集合
DirectoryInfo[] dirSub = dir.GetDirectories();
if(dirSub.Length==0)
{
//如果沒有子目錄了則添加進列表
dirList.Add(dir);
return;
}
foreach (DirectoryInfo subItem in dirSub)
{
//跳過系統目錄
if (!system && (subItem.Attributes & FileAttributes.System)==FileAttributes.System)
{
continue;
}
//跳過隱藏目錄
if (!hidden && (subItem.Attributes & FileAttributes.Hidden)==FileAttributes.Hidden)
{
continue;
}
//遞歸
GetEndDirectories(subItem, dirList);
}
}
catch (Exception ex)
{
MessageBox.Show("獲取目錄層級失敗。" + ex.Message);
}
}
2、創建相應模塊
當存在一個DLL時,就生成一個模塊,兩個DLL時就要有兩個模塊,以此類推……
/// <summary>
/// 創建功能按鈕
/// </summary>
/// <param name="toolsInterface"></param>
/// <returns></returns>
private UIElement CreateFunction(IToolsInterface toolsInterface)
{
Button btn = new Button();
btn.Click += Btn_Click;
btn.Content = toolsInterface.ToolName;
btn.Width = 100;
btn.Height = 50;
btn.Margin = new Thickness(5, 0, 0, 0);
btn.Background = toolsInterface.BackgroundBrush;
btn.Foreground = toolsInterface.ForgroundBrush;
btn.Tag = toolsInterface;
return btn;
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
if(btn!=null)
{
IToolsInterface toolsInterface = btn.Tag as IToolsInterface;
if(toolsInterface !=null)
{
FrameworkElement control = toolsInterface.RunToolApplication();
gUc.Children.Clear();
gUc.Children.Add(control);
}
else
{
MessageBox.Show("實例化接口失敗");
}
}
else
{
MessageBox.Show("實例化按鈕失敗");
}
}
3、加載模塊
private void LoadWidgets()
{
string applicationPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
string dirPath = applicationPath + "Widgets/";
if(!Directory.Exists(dirPath))
{
MessageBox.Show("未找到相關的Widgets文件夾信息,請確認相關的文件夾是否存在。");
return;
}
DirectoryInfo dir = new DirectoryInfo(dirPath);
List<DirectoryInfo> lastDirNameList = new List<DirectoryInfo>();
Tools.FileToolsHelper.GetEndDirectories(dir, lastDirNameList);
foreach (DirectoryInfo item in lastDirNameList)
{
WrapPanel wrapPanel = null;
TabItem tabItem = Tools.UCToolsHelper.CreateTabByDirName(item.Name,tcToolkClass);
wrapPanel = Tools.UCToolsHelper.CreateWrapPanel(tabItem);
string[] dllFilesPath = Directory.GetFiles(item.FullName, "*.dll");
foreach (string dllPath in dllFilesPath)
{
Assembly assembly = Assembly.LoadFile(dllPath);
Type[] types = assembly.GetExportedTypes();
foreach (Type type in types)
{
if(typeof(IToolsInterface).IsAssignableFrom(type)&&!type.IsAbstract)
{
IToolsInterface toolInterface = Activator.CreateInstance(type) as IToolsInterface;
if (toolInterface !=null)
{
wrapPanel.Children.Add(CreateFunction(toolInterface));
}
}
}
}
}
}
三、寫相應的模塊部分
最近也沒寫什麼小東西,就把原來做的兩個Winform東西,直接搬過來,弄成了WPF的,把窗體改成了UserControl,額外加了一個類,用來實現第一部分提到的接口。
其中一個小工具在這:http://www.cnblogs.com/ZXdeveloper/p/5682230.html
基本東西不動,只是加了一個FunctionHelper用來實現接口,此處需要注意,一定是Public,否則查詢不到
public class FunctionHelper : IToolsInterface
{
public Brush BackgroundBrush
{
get
{
return new SolidColorBrush(Colors.LightBlue);
}
}
public Brush ForgroundBrush
{
get
{
return new SolidColorBrush(Colors.YellowGreen);
}
}
public bool IsPopUp
{
get
{
return false;
}
}
public string ToolName
{
get
{
return "方法查詢工具";
}
}
public FrameworkElement RunToolApplication()
{
return new SearchUC();
}
}
四、看一下效果圖

大概也就這麼一個流程,不是很難,方便了後期的開發。
DEMO還有很多不完善的地方,我會慢慢弄,後期會不斷的完善
DEMO