在插件中使用自定义附加属性会导致Reflection / CreateInstance出错

问题描述 投票:0回答:1

我正在开发一个程序,在给定目录中搜​​索“plugins”(即.DLL文件),然后加载它们(使用Reflection)。到目前为止一切正常。但是,如果我现在在插件项目中创建一个Dependency属性并想要使用它,程序崩溃时会显示一条错误消息:

抛出异常:PresentationFramework.dll中的“System.Windows.Markup.XamlParseException”未实现方法或操作。

只有在插件项目中创建DP时才会发生这种情况。如果我使用现有的(也添加了自己,但已经存在,因为它包含在API中)一切正常,没有错误或其他任何东西。顺便说一下,至少根据Visual Studio,在Activator.CreateInstance(t)中发生错误。

有趣的是,如果我将一个WPF项目添加到插件的项目(这是一个类库),链接到插件和API,并包含在主窗口中使用附加属性的UserControl,一切正常。所以它必须与我动态加载插件有关,但我不知道它可能是什么。特别是因为,正如我所说,以前创建的DP工作正常,只有我在插件中创建的DP没有。

我想写一个“重现步骤”代码,但我担心它不会那么容易。该程序现在已经相当复杂,只是为了隔离这个问题可能很困难。下面是加载插件的代码,附加属性,附加属性的基类以及我想要使用它的.xaml文件。

加载插件:

public void LoadPlugins()
{
    var path = Directory.GetCurrentDirectory() + "\\plugins\\";

    Assembly asm;
    foreach (var plugin in Directory.GetFiles(path, "*.dll"))
    {
        asm = Assembly.LoadFrom(plugin);
        foreach (var t in asm.GetTypes())
        {
            if (t.GetInterface("RemotyAPI") != null && (t.Attributes & TypeAttributes.Abstract) != TypeAttributes.Abstract)
            {
                var pluginInstance = (RemotyAPI)Activator.CreateInstance(t);

                var p = new Plugin
                {
                    Name = t.Name,
                    Title = pluginInstance.Name,
                    Version = pluginInstance.Version,
                    LogoPath = pluginInstance.LogoPath,
                    Instance = pluginInstance
                };

                p.Instance.SendMessage += Server.GetInstance().SendMessage;

                Plugins.Add(p);
            }
        }
    }
}

我附加属性的基类:

public abstract class BaseAttachedProperty<Parent, Property>
    where Parent : new()
{
    public event Action<DependencyObject, DependencyPropertyChangedEventArgs> ValueChanged = (sender, e) => { };

    public static Parent Instance { get; private set; } = new Parent();

    public static readonly DependencyProperty mValueProperty = DependencyProperty.RegisterAttached("Value", typeof(Property), typeof(BaseAttachedProperty<Parent, Property>), new UIPropertyMetadata(new PropertyChangedCallback(OnValuePropertyChanged)));

    private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (Instance as BaseAttachedProperty<Parent, Property>)?.OnValueChanged(d, e);

        (Instance as BaseAttachedProperty<Parent, Property>)?.ValueChanged(d, e);
    }

    public static Property GetValue(DependencyObject d)
    {
        return (Property)d.GetValue(mValueProperty);
    }

    public static void SetValue(DependencyObject d, Property value)
    {
        d.SetValue(mValueProperty, value);
    }

    public virtual void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { }
}

附属物本身:

public class SubHeading : BaseAttachedProperty<SubHeading, string> { }

SystemStatsUI.xaml中的T​​extblock(我想使用该属性的UserControl):

<TextBlock local:SubHeading.Value="Test" />

Visual Studio编译没有问题,没有警告或其他任何东西。但是一旦我启动主程序并尝试加载插件,它就会崩溃。但是如果我现在注释掉我使用DP的TextBlock,那么一切都会再次起作用,除了不使用DP。但它确实存在,或者说它至少是创造出来的。正如我所说,它只在动态加载时才起作用。如果我将WPF项目添加到插件项目并绑定到用户控件中,我可以毫无问题地使用DP。但不是在主程序中,我只能使用主程序的预定义DP而不会出现问题。

实施杰夫的想法:

MainWindowViewModel构造函数:

    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    ....
}

CurrentDomain_AssemblyResolve:

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    var path = Directory.GetCurrentDirectory() + "\\plugins\\";
    return Assembly.LoadFrom(path + args.Name);
}

它跳转到回调函数,但要求一个.resources文件,它在plugins文件夹中找不到。但我不知道它应该在哪里找到它,它也不存在于我的插件文件夹中。或者我应该只通过将.dll作为文件末尾的请求?

c# wpf reflection dependency-properties
1个回答
0
投票

我相信问题可能是动态加载程序集的加载上下文。它位于LoadFrom上下文中,因此xaml解析器无法正确解析它,因为它在默认的加载上下文中运行。

您将需要添加一个自定义程序集解析程序来处理xaml解析器的运行时解析。

asm = Assembly.LoadFrom(plugin); // your current code...just add the below line of code
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
  new AssemblyName(args.Name).Name == asm.GetName().Name ? asm : null;

另外 - 绝对确保你的插件dll目录和bin目录之间没有任何重复的dll - 你会得到“组件没有资源标识符”你提到的那种错误。

© www.soinside.com 2019 - 2024. All rights reserved.