Совместно используемые словари Silverlight - PullRequest
4 голосов
/ 11 ноября 2010

Я использую Silverlight 4 и пытаюсь поделиться некоторыми общими стилями (цвета, кисти). Я решил поместить их в словарь ресурсов Common.xaml, а затем использовать его во всех других словарях ресурсов. Ссылка на все так:

<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, заявляющее, что общие стили не могут быть найдены (Не удается найти ресурс с именем / ключом ....)

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

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

Ответы [ 4 ]

4 голосов
/ 12 ноября 2010

Проблема в том, что 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)});

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

1 голос
/ 05 апреля 2011

Мне удалось настроить решение, предложенное на 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 голосов
/ 09 марта 2013

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

0 голосов
/ 07 марта 2013

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

//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));

Грег

...