Динамические ресурсы уровня приложения не являются динамическими при размещении в ElementHost

Я размещаю WPF UserControl в контейнере WinForms. Теперь я хочу иметь возможность создать тему / скин для UserControl. Для этого у меня есть несколько словарей ресурсов, которые определяют «скины». Когда мое приложение запускается, я создаю «новый System.Windows.Application ()», так что Application.Current существует. Чтобы изменить тему, старый скин удаляется, а новый скин добавляется в словарь ресурсов уровня приложения во время выполнения. Однако это не меняет ни один из динамически связанных ресурсов в UserControl. Я пробовал это в обычном приложении WPF, и он работал нормально. Я что-то упускаю или это вообще невозможно сделать? Кстати, если я добавлю скин в ресурсы приложения до инициализации UserControl, он будет работать, но после этого я не смогу изменить скин.

Чтобы сделать это самым простым способом:

Создайте новое приложение WinForms. Добавьте в приложение WPF UserControl. Это достаточно просто:

<UserControl ...>
   <Grid>
      <Button
         Background="{DynamicResource ButtonBG}"/>
   </Grid>
</UserControl>

Создайте два ResourceDictionaries, White.xaml и Black.xaml (или что-то еще), которые имеют SolidColorBrush с ключом ButtonBG с соответствующим цветом. В Form1.cs добавьте две кнопки и ElementHost. Установите дочерний элемент ElementHost в экземпляр только что созданного UserControl. Подключите кнопки к событиям, которые меняют скин:

private void White_Click(object sender, EventArgs e)
{
   Application.Current.Resources.MergedDictionaries[0] = 
      (ResourceDictionary)Application.LoadComponent(
         new Uri(@"\WpfThemes;component\White.xaml", UriKind.Relative)));
}

private void Black_Click(object sender, EventArgs e)
{
   Application.Current.Resources.MergedDictionaries[0] = 
      (ResourceDictionary)Application.LoadComponent(
         new Uri(@"\WpfThemes;component\Black.xaml", UriKind.Relative)));
}

В Program.cs убедитесь, что Application.Current существует, и установите начальный скин:

[STAThread]
static void Main()
{
   new System.Windows.Application();

   Application.Current.Resources.MergedDictionaries[0] =
      (ResourceDictionary)Application.LoadComponent(
         new Uri(@"\WpfThemes;component\White.xaml", UriKind.Relative)));

   ...
}

Теперь, когда нажата кнопка White, я ожидал, что кнопка в UserControl станет белой, а когда нажата кнопка Black, я ожидал, что кнопка станет черной. Однако этого не происходит.

Кто-нибудь знает почему? Есть ли решение?

Изменить: Идея: возможно, если есть способ принудительно переоценить DynamicResources при изменении темы, это сработает.

Спасибо, Дасти


person dustyburwell    schedule 07.04.2009    source источник


Ответы (2)


Я думаю, что это может быть упущенная проблема в структуре WPF.

Из того, что я могу сказать через Reflector, похоже, что когда словарь ресурсов Application катастрофически изменяется (изменение, которое, вероятно, будет иметь широкий спектр эффектов, таких как добавление, удаление или замена оболочки), есть код, который циклически перебирает все Windows в приложении и заставляет их пересмотреть свои DynamicResources. Однако другие элементы, которые я бы считал верхним уровнем в WPF, например ElementHosts, не обрабатываются таким же образом. Это приводит к тому поведению, которое я испытываю.

Мое решение этой проблемы - вручную просмотреть все мои ElementHost по отдельности и добавить, удалить или заменить файл обложки ResourceDictionary. Он не идеален, но выполняет свою работу.

person dustyburwell    schedule 01.05.2009
comment
привет Дастибурэлл, не могли бы вы предоставить образец кода? - person user1912383; 27.11.2015

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

Единственное, что вы должны напомнить, - никогда не показывать окно (-> исключение) и закрывать его при удалении elementhost, чтобы приложение могло завершиться должным образом.

person lola0011    schedule 24.07.2014