Как использовать словарь ресурсов в призменных модулях во время разработки? - PullRequest
7 голосов
/ 17 августа 2011

Я использую платформу призмы в приложении silverlight с несколькими модулями в отдельных XAP.

В моем проекте оболочки определен словарь ресурсов.В моих модулях я могу нормально использовать ресурсы, но поскольку модули отсоединяются от оболочки до тех пор, пока они не загружены во время выполнения, конструктор не показывает их и не распознает их.

Есть ли способ заставить модули знатьиз моих ресурсов во время разработки без слияния моего файла ресурсов в каждом представлении xaml?

Мои файлы ресурсов находятся в «общем» проекте.

Ответы [ 4 ]

5 голосов
/ 23 мая 2012

Я думаю, что у меня определенно есть решение для ресурсов времени разработки.

Преимущества:

  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 будет загружаться только при необходимости.

Пример использования:

включает SharedResourceDictionary в App.xaml

<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
  </ResourceDictionary>
</Application.Resources>

включает SharedResourceDictionary везде, где дизайнер не может найти некоторый общий ресурс, например в MyApp.Module1 / UserControl1.xaml

<UserControl.Resources>
  <common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</UserControl.Resources>

Источник:

/// <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;
  }
}
4 голосов
/ 16 ноября 2011

Я обнаружил, что есть несколько решений для этого:

1) Когда вы создаете проект модуля, оставьте App.xaml в проекте вместо его удаления и создайте в нем свои ресурсы так же, какесли бы это было его собственное приложение (вы также можете добавить новый класс Application в проект, если вы уже удалили его).Когда ваш модуль загружается в оболочку, этот файл будет игнорироваться, поэтому он действителен только во время разработки.Это хорошо работает в Visual Studio и смешивается, хотя, если у вас много модулей, использование памяти может стать проблемой.

2) Использование ресурсов времени проектирования.Некоторая информация о настройке здесь: http://adamkinney.com/blog/2010/05/04/design-time-resources-in-expression-blend-4-rc/. Это предлагает только поддержку смешивания, и ваши представления будут лишены всех стилей и форматирования в Visual Studio.Это было не идеально для меня, потому что мне нравится работать над некоторыми аспектами пользовательского интерфейса в визуальной студии.Также не существует документированного способа ручной настройки ресурсов времени разработки.

2 голосов
/ 16 февраля 2016

Небольшое руководство по собственному опыту по переносу ресурсов из Shell в совместную сборку и созданию отличной работы дизайнера

Некоторые мысли, основанные на прочтении таких вопросов и поиске в Интернете той же / подобной проблемы,Я пишу это в первую очередь из-за проблемы 2 (ниже), которая связана с этой проблемой, ИМХО.

Итак, у нас был одинаковый дизайн, все стили и ресурсы были в Shell.Это вызвало 2 проблемы:

  1. Контекстная справка в XAML-редакторе недоступна (<- ресурсы не найдены) </li>
  2. Конструктор не будет отображаться правильно (<- ресурсы не найдены)</li>

Таким образом, мы перенесли все стили в общую сборку (Ресурсы).

Чтобы решить первую проблему, вам понадобится что-то вроде предложенного Liero, то есть добавить словарь ресурсов в каждый UserControl.Я не пробовал его SharedDictionary, но обычный ResourceDictionary определенно возвращает контекстную справку и удаляет строки с синим подчеркиванием.Дизайнер, однако, все еще не показывался должным образом.

Итак, вторая проблема.Есть небольшая хитрость, чтобы привести стили к дизайнеру во время разработки, описанную только в этой статье .По сути, вы добавляете словарь ресурсов с именем DesignTimeResources.xaml в ваш проект, который содержит ссылку на ваши ресурсы:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml"/>
    </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

Чем переместить его в папку «Свойства».Затем отредактируйте вручную проектный файл и измените элемент для этого файла следующим образом:

<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
      <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
    </Page>

По сути, это файл, который Blend сгенерирует, если вы добавите ресурсы времени разработки.VS не может создать это, хотя может прочитать это просто отлично.Редактирование файла проекта говорит о том, что вы не хотите в основном этот файл в релизе.

Здесь также есть две незначительные ошибки, возможно, это кому-нибудь поможет.

  • При переносе ресурсов из Shell в Resources наш проект Resources не будет работать со странными ошибками, из-за которых он не сможет найти элементы управления UserControls, на которые ссылаются файлы стилей (все проблемные элементы управления также были определены в проекте Resources).Они работали очень хорошо, когда ссылались из Shell прежде.Проблема заключалась в том, что некоторые инструменты (например, Resharper) автоматически ссылаются на эти элементы управления в пространстве имен, например "clr-namespace:XXX;assembly=Resources".";assembly=Resources" - часть, которую вы должны удалить, поскольку теперь это та же самая сборка.
  • Мы уже используем некоторые локальные ресурсы в наших пользовательских элементах управления, например:

    <UserControl.Resources>
        <PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
    </UserControl.Resources>
    

Итак, сначала я только добавил новый ResourceDictionary в этот блок, который попросил меня предоставить ключ x :.Я так привык добавлять ресурсы непосредственно в UserControl.Resources, что сначала не осознавал, что для объединения другого словаря вам понадобится тег <ResourceDictionary>, который обычно можно пропустить.Так это будет выглядеть так:

<UserControl.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <Helpers:RedbexResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml" />
    </ResourceDictionary.MergedDictionaries>
    <PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
  </ResourceDictionary>
</UserControl.Resources>
1 голос
/ 11 октября 2011

Если вы хотите предоставить данные о времени разработки для ваших представлений, я могу предложить прочитать эту статью .В нем показано, как использовать Blend для создания данных времени разработки в вашем проекте, которые не включены в выпуски сборки приложения.

Надеюсь, это поможет.

...