【问题标题】:Dynamic Application-level resources are not dynamic when hosted in ElementHost动态应用程序级资源在 ElementHost 中托管时不是动态的
【发布时间】:2009-04-07 18:56:29
【问题描述】:

我在 WinForms 容器中托管 WPF UserControl。现在,我希望能够为 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 中,添加两个 Button 和一个 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)));

   ...
}

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

有人知道为什么吗?有解决办法吗?

编辑:想法:也许,如果有办法在主题更改时强制重新评估 DynamicResources,那会奏效。

谢谢, 尘土飞扬

【问题讨论】:

    标签: wpf winforms-interop elementhost


    【解决方案1】:

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

    据我通过 Reflector 得知,似乎当 Application 资源字典发生灾难性更改(可能会产生广泛影响的更改,例如添加、删除或替换皮肤)时,会出现循环代码覆盖应用程序中的所有Windows,并迫使他们重新评估他们的DynamicResources。但是,我会在 WPF 中考虑 顶级 的其他元素(例如 ElementHosts)没有得到相同的处理。这导致了我正在经历的行为。

    我对这个问题的解决方法是手动检查我的所有ElementHosts 并添加、删除或替换皮肤ResourceDictionary 文件。它并不完美,但它可以完成工作。

    【讨论】:

    • 你好dustyburwell,你能提供一个示例代码吗?
    【解决方案2】:

    博士。当我试图做类似的事情时,WPF 来拯救我。他展示了如何在 WinForms 中创建 Application 对象。现在您可以像在 WPF 应用程序中一样将所有内容都引用为 StaticResource。

    http://drwpf.com/blog/2007/10/05/managing-application-resources-when-wpf-is-hosted/

    【讨论】:

      【解决方案3】:

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

      你应该提醒的唯一一件事是永远不要显示窗口(-> 异常),并在处理 elementhost 时关闭它,以便应用程序可以正常关闭。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-09
        • 1970-01-01
        • 2014-12-12
        • 1970-01-01
        • 2012-09-07
        • 2013-09-12
        相关资源
        最近更新 更多