• 模块式开发


    这两天看到同事的一个小工具,用的是模块式开发,也就是俗称的插件开发,用的是反射+接口的方式实现的。感觉挺好的,也就学习了一下,写个小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

  • 相关阅读:
    Socket_leaks open socket #5024 left in connection
    阿里云 如何减少备份使用量? mysql数据库的完整备份、差异备份、增量备份
    一个正则式引发的血案 贪婪、懒惰与独占
    linux下tmp目录里很多php开头的文件
    后端线上服务监控与报警方案
    架构先行
    数据盘缩容
    文件过滤 批量删除
    mock数据(模拟后台数据)
    如何避免升级 Linux 实例内核后无法启动
  • 原文地址:https://www.cnblogs.com/ZXdeveloper/p/5959476.html
Copyright © 2020-2023  润新知