2010-11-11 1 views
4

Я использую Silverlight 4 и пытаюсь поделиться некоторыми общими стилями (цветами, кистями). Мой прием заключался в том, чтобы поместить их в словарь ресурсов Common.xaml, а затем использовать его во всех других ресурсо-словарях. Реферирование все так:Silverlight Shared MergedDictionaries

<Application 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="SampleApp.App" 
> 
    <Application.Resources> 

    <ResourceDictionary> 

     <ResourceDictionary.MergedDictionaries> 
     <ResourceDictionary Source="Assets/Styles/Common.xaml"/> 
     <ResourceDictionary Source="Assets/Styles/TextBoxStyle.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 

    </ResourceDictionary> 

    </Application.Resources> 

</Application> 

Проблема заключается в том, что я получаю исключение на InitializeComponent о том, что общие стили не могут быть найдены (не удается найти ресурс с именем/Key ....)

Я должен явно ссылаться на «Common.xaml» в каждом словаре ресурсов, где я его использую ... И это в основном приводит к множеству экземпляров каждого цвета, кисти, шаблона и еще чего-то, что находится в «Common.xaml».

Разве нет возможности делиться Ресурсами, так что только один раз в Silverlight?

ответ

4

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

С ResourceDictionary не имеет встроенных средств для описания взаимозависимостей или события, указывающего, когда оно загрузилось, единственным решением, к которому я пришел, является управление загрузкой самих словарей.

Вот функция, которую можно добавить к App.xaml.cs файл в «вручную» загрузить словарь ресурсов: -

private void LoadResource(Uri uri) 
    { 
     var info = Application.GetResourceStream(uri); 
     string xaml; 
     using (var reader = new StreamReader(info.Stream)) 
     { 
      xaml = reader.ReadToEnd(); 
     } 

     ResourceDictionary result = XamlReader.Load(xaml) as ResourceDictionary; 

     if (result != null) 
     { 
      Resources.MergedDictionaries.Add(result); 
     } 
    } 

Теперь в Application_Startup перед назначением RootVisual вы бы использовать такой код: -

LoadResource(new Uri"Assets/Styles/Common.xaml", UriKind.Relative)); 
    LoadResource(new Uri("Assets/Styles/TextBoxStyle.xaml", UriKind.Relative)); 

это не собирается быть столь же эффективным, как использование Source собственности, но он будет работать. Если у вас есть много таких словарей и только несколько «общих» словарей, которые содержат общие ресурсы, то вы могли бы использовать эту технику, чтобы загрузить только «общие» словари затем использовать: -

Resource.MergedDictionaries.Add(new ResourceDictionary() {Source = new Uri("Assets/Styles/TextBoxStyle.xaml", UriKind.Relative)}); 

Для других словарей, которые не имеют взаимозависимости друг с другом.

+0

Фантастическое решение, спасибо! Мне пришлось изменить ваши вызовы LoadResource следующим образом: LoadResource (новый Uri («ProjectResources; компонент/Resources/Stylesheets/ComboBox.xaml», UriKind.Relative)); Когда я попробовал ваш пример, я получил исключение, что Uri не был поддержан. Кроме того, вы теряете проектный вид в Blend, когда он находится на своем месте. Я не очень люблю разработчика, поэтому я просто комментирую/раскомментирую приложение app.xaml для стилей. – dex3703

1

Я смог настроить решение, предложенное в http://www.wpftutorial.net/MergedDictionaryPerformance.html , чтобы он работал с Silverlight и дизайнером VS (не пробовал Blend). У меня есть запись в блоге на него здесь (http://softnotes.wordpress.com/2011/04/05/shared-resourcedictionary-for-silverlight/)

public class SharedResourceDictionary : ResourceDictionary 
{ 
    public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries = 
     new Dictionary<Uri, ResourceDictionary>(); 

    private Uri _sourceUri; 
    public new Uri Source 
    { 
     get { return _sourceUri; } 
     set 
     { 
      _sourceUri = value; 
      if (!_sharedDictionaries.ContainsKey(value)) 
      { 
       Application.LoadComponent(this, value); 
       _sharedDictionaries.Add(value, this); 
      } 
      else 
      { 
       CopyInto(this, _sharedDictionaries[value]); 
      } 
     } 
    } 

    private static void CopyInto(ResourceDictionary copy, ResourceDictionary original) 
    { 
     foreach (var dictionary in original.MergedDictionaries) 
     { 
      var mergedCopy = new ResourceDictionary(); 
      CopyInto(mergedCopy, dictionary); 
      copy.MergedDictionaries.Add(mergedCopy); 
     } 
     foreach (DictionaryEntry pair in original) 
     { 
      copy.Add(pair.Key, pair.Value); 
     } 
    } 
} 

использование XAML:

<ResourceDictionary.MergedDictionaries> 
    <ui:SharedResourceDictionary Source="/my_assembly_name;component/Resources/Shared.xaml"/> 
</ResourceDictionary.MergedDictionaries> 
0

Если вы получаете нагрузку ошибки, убедитесь, что Сложение Действие устанавливается в одно из следующих действий:

//In the dll, which is in the xap, marked as Build Action: Resource or Page 
LoadResource(new Uri("SilverlightApplication48;component/GlobalAssets.xaml", UriKind.Relative)); 

//In the xap at the same level as the dll, (not in the dll) marked as Build Action: Content. 
LoadResource(new Uri("Dictionary1.xaml", UriKind.Relative)); 

//In a separate library, marked as Build Action: Resource or Page. 
LoadResource(new Uri("StylesLibrary;component/Dictionary2.xaml", UriKind.Relative)); 

Грег

0

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