簡體   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