如何在ItemsControl生成其容器之前或之后更改加载的主题资源字典,但在那时不更改?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在ItemsControl生成其容器之前或之后更改加载的主题资源字典,但在那时不更改?相关的知识,希望对你有一定的参考价值。

我动态加载应用程序资源字典(一次加载3个中的2个:]

  1. 始终是基本资源字典
  2. Light.xaml主题文件
  3. 一个Dark.xaml主题文件

如果主窗口已经为MergedDictionaries时通常更改Loaded属性的值,则会出现异常(调用堆栈here):

System.InvalidOperationException:'在内容生成过程中无法调用StartAt。'

[如果我使用MergedDictionaries更改Dispatcher.BeginInvoke属性的值,则当我在(1)的代码隐藏中使用资源时,它会通过一个异常表示该资源尚未加载(例如,通过StaticResource使用资源那不存在)。

我不想使用App.xaml文件,因为对于具有单实例应用程序,我使用了一个从Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase继承并调用App.cs文件中的代码的类。

我可以在应用程序代码中的几个地方调用LoadTheme方法,并且我想使其稳定。

App.cs

(no XAML)

public class App : System.Windows.Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        LoadTheme(AppTheme.Light);
        var w = new MainWindow();
        ShutdownMode = ShutdownMode.OnMainWindowClose;
        MainWindow = w;
        w.Show();
    }
    internal ResourceDictionary MLight = null,
        MDark = null,
        MMain = null;
    internal ResourceDictionary GetLightThemeDictionary()
    {
        if (MLight == null)
        {
            MLight = new ResourceDictionary() { Source = new Uri("Themes/Light.xaml", UriKind.Relative) };
        }
        return MLight;
    }
    internal ResourceDictionary GetDarkThemeDictionary()
    {
        if (MDark == null)
        {
            MDark = new ResourceDictionary() { Source = new Uri("Themes/Dark.xaml", UriKind.Relative) };
        }
        return MDark;
    }
    internal ResourceDictionary GetMainDictionary()
    {
        if (MMain == null)
        {
            MMain = new ResourceDictionary() { Source = new Uri("AppResources.xaml", UriKind.Relative) };
        }
        return MMain;
    }
    internal void LoadTheme(AppTheme t)
    {
        //Dispatcher.BeginInvoke(new Action(() =>
        //{
            if (Resources.MergedDictionaries.Count == 2)
            {
                switch (t)
                {
                    case AppTheme.Dark:
                        Resources.MergedDictionaries[1] = GetDarkThemeDictionary();
                        break;
                    default:
                        Resources.MergedDictionaries[1] = GetLightThemeDictionary();
                        break;
                }
            }
            else if (Resources.MergedDictionaries.Count == 1)
            {
                switch (t)
                {
                    case AppTheme.Dark:
                        Resources.MergedDictionaries.Add(GetDarkThemeDictionary());
                        break;
                    default:
                        Resources.MergedDictionaries.Add(GetLightThemeDictionary());
                        break;
                }
            }
            else
            {
                Resources.MergedDictionaries.Clear();
                Resources.MergedDictionaries.Add(GetMainDictionary());
                LoadTheme(t);
            }
        //}), System.Windows.Threading.DispatcherPriority.Normal); // how to process this after the ItemsControl has generated its elements?
    }
}

我试图做一个测试示例,但是失败了-我创建了一个有效的程序,因为每次应用模板时都会设置ItemsControl.ItemsSource。在我的实际项目中,我通过数据绑定(有时是手动设置)来设置ItemsSource,但是我不确定这是我的实际项目中缺少的内容。

我使用.NET Framework 4.7.2,VS 2019,Win 10 Pro。

谢谢。

答案
OnStartup方法现在看起来像这样(在构建MainWindow之前,我刚刚加载了基础词典和一个主题):

以上是关于如何在ItemsControl生成其容器之前或之后更改加载的主题资源字典,但在那时不更改?的主要内容,如果未能解决你的问题,请参考以下文章

ItemsControl 上的 WPF MVVM 单选按钮

在部署到Servlet容器之前,如何生成包含SpringBoot的War文件

如何在gmail中发送电子邮件之前或之后获取消息ID? [复制]

如何获取包含 ItemsControl 内容的 Panel 实例?

在 WPF ItemsControl 中绕过栅栏原则

KafkaContainer - 如何在启动()之后在 Spring Boot 中读取 kafka 容器端口作为属性 / 如何在启动之前配置 Kafka 端口