在ElementHost中托管时,动态应用程序级资源不是动态的

时间:2009-04-07 18:56:30

标签: wpf winforms-interop elementhost

我在WinForms容器中托管WPF UserControl。现在,我希望能够主题/皮肤UserControl。为此,我有几个定义“皮肤”的资源字典。当我的应用程序启动时,我创建了一个“new System.Windows.Application()”,以便Application.Current存在。要更改主题,将删除旧外观,并在运行时将新外观合并到应用程序级别资源字典中。但是,这不会更改UserControl中任何dyanamically引用的资源。我在一个直接的WPF应用程序中尝试了这个,它运行得很好。我错过了什么,或者根本不可能这样做?顺便说一下,如果我在UserControl初始化之前将一个皮肤添加到应用程序资源中,它将起作用,但之后我无法更改皮肤。

以最基本的方式回复:

创建一个新的WinForms应用程序。将WPF UserControl添加到应用程序。这很简单:

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

使用具有相应颜色的键ButtonBG创建两个具有SolidColorBrush的ResourceDictionaries,White.xaml和Black.xaml(或其他)。在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)));

   ...
}

现在,当单击白色按钮时,我希望UserControl中的按钮变为白色,当单击黑色按钮时,我希望按钮变黑。但是,这不会发生。

有谁知道为什么?有解决方案吗?

编辑:想法:也许,如果有一种方法可以在主题发生变化时强制重新评估DynamicResources,那就可以了。

谢谢, 多尘

2 个答案:

答案 0 :(得分:6)

我认为这可能是WPF框架中一个被忽视的问题。

从我通过Reflector可以看出,当Application资源字典发生灾难性变化时(一种可能具有广泛影响的变化,如添加,删除或替换皮肤),似乎有代码它遍历应用程序中的所有Windows并强制他们重新评估他们的DynamicResources。但是,我在WPF中考虑 top-level 的其他元素(例如ElementHost)并没有得到相同的处理。这导致了我正在经历的行为。

我对这个问题的解决方法是手动遍历我的所有ElementHost并添加,删除或替换皮肤ResourceDictionary文件。它并不完美,但它完成了工作。

答案 1 :(得分:-1)

另一种解决方法是创建一个虚拟窗口并将elementhost的内容指定为内容。 如果您查看应用程序并检查它如何处理资源的更改,您会看到它只通知窗口..

你唯一应该提醒的是永远不要显示窗口( - &gt;异常),并在处理elementhost时关闭它,这样应用程序就可以正常关闭。