Revit—WPF类库不明原因的不能加载?

本文探讨了Revit二次开发中使用Wpf界面遇到的第三方DLL加载问题,提供了一种优雅的解决方案,即在启动时主动加载DLL,避免了将DLL复制到Revit安装目录的传统做法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      乱语:

     你打发无聊时间的方法,决定了你的成色。

     今天是庚子年一月一日,就是俗话说的大年初一。全国被新型冠状病毒引发的传染病所笼罩,当看到那些冲向灾区的逆行者,除了泪目之外,还从心底发出一定要做点儿什么的急切心愿。

      我们这些做程序的,自嘲了称呼声码农,往大了说那也是工程师,留下点儿有用于世间的东西吧。于是写下了这篇文章。

    正文:

     问题背景

       现在搞Revit二次开发的人越来越多,一些外界人才的涌入,终于冲击到了那些非程序专业人搞二次开发的一些顽固想法。市面上,Revit二次开发产品UI也慢慢的由传统的Winform向Wpf过度。现在似乎已经没有人在问那种我用Winform挺好的,为什么要换成Wpf的守旧问题。但是还是要强答一波,因为Revit的UI,起码菜单是Wpf开发的,所以二次开发最好就用Wpf。其他的优劣对比,一概懒得说了。

      但使用Wpf开发的类库有一个问题。您大概也是因为这个问题才检索到我这篇文章的。我们使用Wpf进行二次开发,一般要把项目编译成dll。随着我们对界面显示或者代码结构的要求越来越高。我们可能会在,我们开发的.xaml窗体中,引用到第三方的dll。如果这个第三方的dll,只是在xaml中被使用了,当我们通过Revit的命令按钮去执行时,可能会发生找不到相关dll的异常,但它的的确确时在插件dll的目录下。

     问题剖析:

      首先明确这不是Revit的问题,Wpf进行dll开发时,确实会出现这种“bug”。如果是自己开发的exe可能没问题,但是dll中xmal解析确实可能存在问题的。至于原因是什么,我们就不去深究了。

      解决问题:

       刚开始的时候,我们发现这个问题,用了很粗暴的方法,就是把加载出异常说找不到的dll记录下来,然后在插件程序安装,或者插件程序启动的时候,把这些dll 拷贝到Revit安装目录下。

      这种方法能解决问题,但是不够优雅。现在有了更好的思路。

      思路很简单,在Revit启动插件的时候,主动的自己去加载那些不能自动解析的dll。

     写了一个小的加载类,供大家参考

  

 /// <summary>
    /// 程序集加载器
    /// </summary>
    public class AssemblyLoader
    {
        /// <summary>
        /// 加载程序集找不到引用时搜索路径
        /// </summary>
        /// <param name="searchPaths"></param>
        public AssemblyLoader(List<string> searchPaths)
        {
            SerachPaths = new ReadOnlyCollection<string>(searchPaths);
        }
        public AssemblyLoader()
        {
            var paths = new List<string>();
            paths.Add(AppDomain.CurrentDomain.BaseDirectory);
            paths.Add(Path.GetDirectoryName( this.GetType().Assembly.Location));
            paths = paths.Distinct().ToList();
            SerachPaths = new ReadOnlyCollection<string>(paths);
        }
        public ReadOnlyCollection<string> SerachPaths { get; private set; }
        #region 公开方法
        /// <summary>
        /// 加载dlls,paths为绝对路径,或者是在相对于当前dll位置的相对路径
        /// </summary>
        /// <param name="paths"></param>
        public void LoadDlls(List<string> paths)
        {
            try
            {
                AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
                foreach (string path in paths)
                {
                    if (File.Exists(path))
                    {
                        try
                        {
                            Assembly.LoadFrom(path);
                        }
                        catch (Exception ex)
                        {
                            Console.Write(ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {

                Console.Write(ex.StackTrace.ToString());
            }
            finally
            {
                AppDomain.CurrentDomain.AssemblyResolve -= OnAssemblyResolve;
            }
        }
        private  Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
        {
            var assemblyName = new AssemblyName(args.Name);
            foreach (var item in SerachPaths)
            {
                var file = string.Format("{0}.dll", Path.Combine(item, assemblyName.Name));
                if (File.Exists(file))
                {
                    try
                    {
                        return Assembly.LoadFrom(file);
                    }
                    catch (Exception ex)
                    {

                    }
                }
            }

            return args.RequestingAssembly;
        }
        #endregion
        #region 静态方法
        private const string PATH = "PATH";
        /// <summary>
        /// 增加路径环境变量
        /// </summary>
        /// <param name="input"></param>
        public static void AddEnvironmentPath(params string[] input)
        {
            var path = new[] { Environment.GetEnvironmentVariable(PATH) ?? string.Empty };
            //加在最前面,
            var newPath = string.Join(Path.PathSeparator.ToString(), input.Concat(path));
            Environment.SetEnvironmentVariable(PATH, newPath);
        }
        #endregion
    }

   然后对这个类进行使用的话,是放在自己实现 IExternalApplication接口的public virtual Result OnStartup(UIControlledApplication application)方法里进行调用。

     AssemblyLoader loader = new AssemblyLoader();
     var dlls = new List<string>();
     dlls.Add("xxx.dll");
     loader.LoadDlls(dlls);

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值