从ClassLibrary加载ResourceDictionary中的XAML文件

时间:2017-07-28 06:29:21

标签: c# wpf xaml mef

我正在尝试创建一个简单的插件系统,其中插件在应用程序启动时从.dll文件动态加载并显示在UI中。

https://css-tricks.com/examples/FullPageBackgroundImage/progressive.php似乎正是我正在寻找的。它使用MEF加载插件。我尝试创建一个简单的项目并按照说明操作。我的解决方案具有以下结构:

  • MeftTest(包含主MefTest.exe,仅引用MefTest.SDK而非插件)
  • MefTest.SDK(包含IPlugin.csIPluginViewModel.cs以及从应用程序目录加载插件的Engine.cs。
  • MefTest.Plugin1(包含第一个插件,引用MefTest.SDK
  • MefTest.Plugin2(包含第二个插件,引用MefTest.SDK

MefTest.SDK - > IPlugin.cs

public interface IPlugin
{
    IPluginViewModel ViewModel { get; }
    ResourceDictionary View { get; }
    string Title { get; }
}

MefTest.SDK - > Engine.cs

public class Engine
{
    [ImportMany]
    private IEnumerable<IPlugin> plugins { get; set; }

    public async Task<ObservableCollection<IPlugin>> GetPlugins()
    {
        try
        {
            var folder = AppDomain.CurrentDomain.BaseDirectory;
            var catalog = new AggregateCatalog();
            //catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryCatalog(folder));
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);

            var result = new ObservableCollection<IPlugin>();

            foreach (var p in plugins)
            {
                result.Add(p);
            }

            return result;
        }
        catch (Exception ex)
        {
            //I get the exception here...
            var t = ex;
            throw;
        }
    }
}

MefTest.Plugin1 - &gt; Plugin1.cs

[Export(typeof(IPlugin))]
public class Plugin1 : IPlugin
{
    private MainViewModel viewModel { get; set; }

    public IPluginViewModel ViewModel
    {
        get { return viewModel; }
    }

    public ResourceDictionary View
    {
        get { return viewDictionary; }
    }

    private ResourceDictionary viewDictionary = new ResourceDictionary();

    public string Title
    {
        get { return "Plugin 1"; }
    }

    [ImportingConstructor]
    public Plugin1()
    {
        //I get the error here. tried both of these, none of them work
        viewDictionary.Source =
        //    new Uri("pack://application:,,,/MefTest.Plugin1;component/views/main.xaml", UriKind.Absolute);
        new Uri("/MefTest.Plugin1;component/views/main.xaml", 
        UriKind.Relative);
    }

    public override string ToString()
    {
        return Title;
    }
}

然而,我收到错误Could not load file or assembly 'MefTest.Plugin1.dll, Culture=neutral' or one of its dependencies. The system cannot find the file specified.

Main.xaml文件位于MefTest.Plugin1\Views\Main.xaml文件夹中。项目的输出类型为ClassLibrary,xaml文件的Build Action为Page

PS:我试图直接引用该插件并在没有MEF(Plugins.Add(new Plugin3.Plugin3());)的情况下添加它,但它仍然抛出相同的异常。所以我认为问题不在于解决方案的MEF部分。

我该如何解决这个问题?此外,这种方法有更好的选择吗?

1 个答案:

答案 0 :(得分:1)

我在xbap应用程序中这样做...来检索远程xaml。尝试对当地的信息做同样的事情

private ResourceDictionary LoadDictionary(string source)
    {
        Stream streamInfo = null;
        ResourceDictionary dictionary = null;

        try
        {
            streamInfo = DistantManager.Instance.GetResource(source);

            if (streamInfo != null)
            {
                Uri baseUri = DistantManager.Instance.GetUri(source);

                dictionary = XamlReader.Load(streamInfo) as ResourceDictionary;

                dictionary.Source = baseUri;
            }
        }
        catch (Exception e)
        {
            BusinessLogger.Manage(e);
            return null;
        }

        return dictionary;
    }

类似

Uri baseUri = new Uri(Mysource);
                dictionary = XamlReader.Load(XXXX) as ResourceDictionary;
                dictionary.Source = baseUri;

但另一方面我不明白为什么你想要一个ResourceDictionary作为你的插件视图......?只需创建插件用户控件??