繁体   English   中英

模块化WPF中的资源(带有Caliburn.Micro和MEF)

[英]Resources in modularized WPF (with Caliburn.Micro and MEF)

我整天都在寻找这个问题的答案,而没有提出任何直接适用于我的情况的解决方案,或者没有任何可行的解决方案(在我发现的情况下适用)。

我设置了一个Caliburn.Micro框架以使用MEF,并且可以很好地加载我的模块化元素。 缺少的一件事是让WPF识别我在一个模块中使用的资源。

如何在我的应用程序引导程序中加载模块

[ImportMany]
private IEnumerable<IMyModule> _myModules;

protected override void Configure()
{
    // Because Configure() is also called from SelectAssemblies(), we cannot instantiate MEF again because it will create conflicts.
    if (_configured)
    {
        return;
    }

    AggregateCatalog aggregateCatalog = new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());
    aggregateCatalog.Catalogs.Add(new DirectoryCatalog(ConfigurationManager.AppSettings["MyModuleFolderLocation"]));
    aggregateCatalog.Catalogs.Add(new AssemblyCatalog(GetType().Assembly));

    _container = new CompositionContainer(aggregateCatalog);

    CompositionBatch batch = new CompositionBatch();
    batch.AddExportedValue<IWindowManager>(new WindowManager());
    batch.AddExportedValue<IEventAggregator>(new EventAggregator());
    batch.AddExportedValue(_container);

    _container.Compose(batch);
    _container.SatisfyImportsOnce(this);

    _configured = true;
}

protected override IEnumerable<Assembly> SelectAssemblies()
{
    // SelectAssemblies() is called before Configure(), so manually force Configure() to run first so that MEF is instantiated properly
    Configure();

    if (!_configured)
    {
        throw new Exception("Unable to configure assemblies");
    }

    List<Assembly> assemblies = new List<Assembly>();

    assemblies.Add(Assembly.GetExecutingAssembly());

    // Need to add all module assemblies so that Caliburn will be able to find the View for a ViewModel
    foreach(IMyModule myModule in _myModules)
    {
        Assembly assembly = myModule.GetType().Assembly;
        assemblies.Add(assembly);
    }

    return assemblies.Distinct();
}

这样可以使模块正确显示。

但是,当模块使用图像时,就永远不会显示该图像,因为这种加载显然没有考虑资源。 我在模块项目中创建一个Resources.resx文件,并向其中添加一个图像。 然后,Visual Studio中提供的图像文件将具有一个“显示资源”和“请勿复制(到输出目录)”的“生成操作”。 这应该意味着图像已嵌入到生成的DLL文件中。

该图像放置在模块项目中的一个名为“ Resources”的文件夹中,XAML像这样使用它:

<Image Source="/Resources/myImage.png" />

该图像显示在Visual Studio的预览中,但在应用程序运行时不显示。

我尝试过的没有用

  • 以另一种方式引用图像: <Image Source="pack://application:,,,/Resources/myImage.png" />
  • 以BAML形式获取资源并将其重新插入执行的程序集,如以下问题所示: 从其他程序集实例化ResourceDictionary xaml (这会在此行上导致OutOfMemoryException var reader = new Baml2006Reader(stream);
  • 还有很多其他参考ResourceDictionary的答案,但是我有一个Resource.resx文件(该文件仅生成不是ResourceDictionary的内部类)

问题仍然存在

如何获取WPF / Caliburn.Micro来识别MEF加载的DLL中的资源?

回答

使用带有Build Action: Resource图像的Source属性使用此语法

<Image Source="/AssemblyName;component/Resources/MyImage.png" />

其中AssemblyName是程序集的名称(在项目属性中定义),/ /Resource/MyImage.png是图像的路径(在项目中定义)。 component必须始终存在。

边注

在@StepUp的大量帮助下,我最初决定使用从该问题中学到的知识来提出一个新问题,并将所有内容重新措辞更具体地针对我的问题。

在写这个新问题时,我最终搜索了可能有助于改写的短语和命令,然后偶然发现了以下页面: http : //www.geekchamp.com/tips/wp7-working-with-images-content-vs -resource建造行动

显然,WPF Image控件具有大量的方法来定义Source属性。 我已经尝试了很多不同的Source输入,并认为我已经尝试了所有这些输入,但是上面链接的页面证明我错了。

据我所能测试,上述语法似乎适用于标有Build Action: Resource图像。 因此,我不再需要图像的RESX文件,并且在引导MEF时不需要任何特殊处理。

首先,您应该使用Style阅读程序集。 然后,有必要使用Baml2006Reader从外部库读取BAML文件。 让我举一个例子:

private GetResourceDictionary()
{
    string address = @"WpfCustomControlLibrary1.dll";
    Assembly skinAssembly = Assembly.LoadFrom(address);
    string[] resourceDictionaries = skinAssembly.GetManifestResourceNames();
    Stream bamlStream = null;            
    string name = "themes/AllStylesDictionary.baml";//themes/AllStylesDictionary.baml
    foreach (string resourceName in resourceDictionaries)
    {
       ManifestResourceInfo info = skinAssembly.GetManifestResourceInfo(resourceName);
       if (info.ResourceLocation != ResourceLocation.ContainedInAnotherAssembly)
       {
          Stream resourceStream = skinAssembly.GetManifestResourceStream(resourceName);
          using (ResourceReader reader = new ResourceReader(resourceStream))
          {
              foreach (DictionaryEntry entry in reader)
              {
                 if (entry.Key.ToString().Equals(name.ToLower()))
                 {
                     bamlStream = entry.Value as Stream;
                 }
              }
          }
        }
    }   
    ResourceDictionary rd = LoadBaml<ResourceDictionary>(bamlStream);
    Application.Current.Resources.MergedDictionaries.Add(rd);
    Style style = Application.Current.Resources.MergedDictionaries[0]["myStyle"] as Style;
    button.Style = style;
}

和:

public static T LoadBaml<T>(Stream stream)
{
   var reader = new Baml2006Reader(stream);
   var writer = new XamlObjectWriter(reader.SchemaContext);
   while (reader.Read())
      writer.WriteNode(reader);
   return (T)writer.Result;
}

更新:

如果要从另一个库加载映像,则应使用以下代码:

yourImage.Source = new Bitmap(System.Reflection.Assembly.GetEntryAssembly().
    GetManifestResourceStream("MyProject.Resources.myimage.png"));

UPDATE1:

要从外部dll加载映像。

foreach (DictionaryEntry entry in reader)
{
   if (entry.Key.ToString().Equals(name.ToLower()))
   {
        bamlStream = entry.Value as Stream;
        BitmapImage bmp = LoadImage(bamlStream);
        img.Source = bmp;
   }
}

public static BitmapImage LoadImage(Stream stream) 
{ 
   BitmapImage bmi; 
   using (MemoryStream ms1 = new MemoryStream()) 
   { 
      stream.CopyTo(ms1); 
      bmi = new BitmapImage(); 
      bmi.BeginInit(); 
      bmi.StreamSource = new MemoryStream(ms1.ToArray()); 
      bmi.EndInit(); 

   } 
   return bmi; 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM