如何在设计时在棱镜模块中使用资源字典?

Ada*_*dam 7 c# silverlight prism mef mvvm

我在一个silverlight应用程序中使用prism框架,在单独的XAP中有多个模块.

我在我的shell项目中定义了一个资源字典.在我的模块中,我可以很好地使用资源,但由于模块与shell分离,直到它们在运行时加载,设计器不会显示它们或识别它们.

有没有办法让模块在设计时知道我的资源而不在每个视图xaml中合并我的资源文件?

我的资源文件位于"常见"项目中.

Lie*_*ero 5

我想我肯定有设计时资源的解决方案.

优点:

  1. 它适用于任何基于模块(MEF,UNITY ..)的应用程序.
  2. 它适用于任何设计师(Visual Studio,Blend ..)
  3. 它不会创建相同ResourceDictionary的多个实例

让我们考虑以下解决方案:

  • MyApp.Shell(.exe)
  • MyApp.Module1(.dll) - 使用MEF在运行时加载
  • MyApp.Module2(.dll) - 使用MEF在运行时加载
  • MyApp.Common(.dll) - 由所有项目引用

您可以在MyApp.Common中定义画笔,隐式样式,模板等.

使用我的SharedResourceDictionary在所有项目中包含ResourceDictionary.在设计时,它将为每个设计器加载ResourceDictionary,在运行时,ResourceDictionary将仅在必要时加载.

用法示例:

包含App.xaml中的SharedResourceDictionary

<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
  </ResourceDictionary>
</Application.Resources>
Run Code Online (Sandbox Code Playgroud)

包括SharedResourceDictionary在内的所有设计师都无法找到一些共享资源,例如在MyApp.Module1/UserControl1.xaml中

<UserControl.Resources>
  <common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</UserControl.Resources>
Run Code Online (Sandbox Code Playgroud)

资源:

/// <summary>
/// Loads singleton instance of ResourceDictionary to current scope;
/// </summary>
public class SharedResourceDictionary : ResourceDictionary
{
  /// <summary>
  /// store weak references to loaded ResourceDictionary, to ensure that ResourceDictionary won't be instanciated multiple times
  /// </summary>
  protected static Dictionary<string, WeakReference> SharedResources = new Dictionary<string, WeakReference>();

  public string SharedSource
  {
    get { return _SharedSource; }
    set
    {
      if (_SharedSource != value)
      {
        _SharedSource = value;
        sharedSourceChanged();
      }
    }
  }
  private string _SharedSource;


  private void sharedSourceChanged()
  {
    //ResourceDictionary will be instanciated only once
    ResourceDictionary sharedResourceDictionary;

    lock (SharedResources)
    {
      WeakReference weakResourceDictionary = null;
      if (SharedResources.ContainsKey(_SharedSource))
      {
        weakResourceDictionary = SharedResources[_SharedSource];
      }
      else
      {
        SharedResources.Add(_SharedSource, null);
      }

      if (weakResourceDictionary == null || !weakResourceDictionary.IsAlive) //load ResourceDictionary or get reference to exiting
      {
        sharedResourceDictionary = (ResourceDictionary)Application.LoadComponent(new Uri(_SharedSource, UriKind.Relative));
        weakResourceDictionary = new WeakReference(sharedResourceDictionary);
      }
      else
      {
        sharedResourceDictionary = (ResourceDictionary)weakResourceDictionary.Target;
      }

      SharedResources[_SharedSource] = weakResourceDictionary;
    }


    if (Application.Current != null)
    {
      //if sharedResourceDictionary is defined in application scope do not add it to again to current scope
      if (containsResourceDictionary(Application.Current.Resources, sharedResourceDictionary))
      {
        return;
      }
    }

    this.MergedDictionaries.Add(sharedResourceDictionary);
  }

  private bool containsResourceDictionary(ResourceDictionary scope, ResourceDictionary rs)
  {
    foreach (var subScope in scope.MergedDictionaries)
    {
      if (subScope == rs) return true;
      if (containsResourceDictionary(subScope, rs)) return true;
    }
    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*dam 4

我发现有几个解决方案:

1)当您创建模块项目时,将 App.xaml 保留在项目中而不是删除它,并在其中实例化您的资源,就像它本身是它自己的应用程序一样(您也可以向项目添加一个新的 Application 类,如果你已经删除了它)。当您的模块加载到 shell 中时,该文件将被忽略,因此它本质上仅在设计时有效。这在 Visual Studio 和 Blend 中效果很好,但如果您有很多模块,内存占用可能会成为问题。

2) 使用设计时间资源。有关此处设置的一些信息:http://adamkinney.com/blog/2010/05/04/design-time-resources-in-expression-blend-4-rc/。这仅提供混合支持,并且您的视图将被删除 Visual Studio 中的所有样式和格式。这对我来说并不理想,因为我喜欢在 Visual Studio 中处理 UI 的某些方面。似乎也没有手动设置设计时资源的记录方法。