我认为这是设计使然。当我们为一个应用创建多个窗口时,每个窗口的行为都是独立的。每个窗口都在自己的线程中运行。每个窗口中使用的Application.Resources也是独立的。
Application.Resources 是一个ResourceDictionary 对象,而ResourceDictionary 类继承自DependencyObject,所以Application.Resources 也是一个DependencyObject 实例。
所有DependencyObject 实例必须在与应用的当前Window 关联的UI 线程上创建。这是由系统强制执行的,这有两个重要含义为您的代码:
有关详细信息,请参阅Remarks 的DependencyObject 下的DependencyObject 和线程。
所以每个Window 都有自己的Application.Resources。在辅助视图中,Application.Resources 是从您的 ResourceDictionary 重新评估的。 BackgroundBrush 不受主视图设置的影响,如下代码所示
(Application.Current.Resources["BackgroundBrush"] as SolidColorBrush).Color = Windows.UI.Colors.Black;
您只是更改与主视图的Window 关联的Application.Current.Resources 实例。
如果您希望辅助视图使用与主视图相同的画笔,我认为您可以将此颜色存储在主视图中,然后在创建辅助视图时应用它。例如,我在App 类中添加了一个名为BackgroundBrushColor 的静态字段,然后像下面这样使用它:
private void ThemeChanger_Click(object sender, RoutedEventArgs e)
{
App.BackgroundBrushColor = Windows.UI.Color.FromArgb(Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255)));
(Application.Current.Resources["BackgroundBrush"] as SolidColorBrush).Color = App.BackgroundBrushColor;
}
private async Task CreateNewViewAsync()
{
CoreApplicationView newView = CoreApplication.CreateNewView();
int newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
(Application.Current.Resources["BackgroundBrush"] as SolidColorBrush).Color = App.BackgroundBrushColor;
Frame frame = new Frame();
frame.Navigate(typeof(SecondaryPage), null);
Window.Current.Content = frame;
// You have to activate the window in order to show it later.
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);
}
我已更改代码以修改每个视图中的资源。如果在更改值之前在 SecondaryPage.xaml.cs 的 ThemeChanged 方法中设置断点,您可以看到资源的值已更改为更新后的值。但它没有反映在视图中。
这里的问题是因为您的ThemeChanged 事件是在主视图中触发的,所以它在主视图的线程中运行,因此您在SecondaryPage.xaml.cs 中使用了ThemeManager_ThemeChanged 方法也将在主视图的线程中运行。这导致ThemeManager_ThemeChanged 方法中的Application.Current.Resources 仍然获得与主视图关联的ResourceDictionary 实例。这就是为什么资源的值已经更改为更新的值并且不会反映在视图中的原因。要清楚地看到这一点,您可以在调试时利用Threads Window。
要解决这个问题,您可以使用this.Dispatcher.RunAsync 方法在正确的线程中运行您的代码,如下所示:
private async void ThemeManager_ThemeChanged(Utils.ThemeManager theme)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
((SolidColorBrush)Application.Current.Resources["BackgroundBrush"]).Color = theme.HighAccentColorBrush.Color;
});
}
但是,您仍然会收到类似这样的错误:“应用程序调用了一个为不同线程编组的接口。”这是因为SolidColorBrush类也继承自DependencyObject。为了解决这个问题,我建议将HighAccentColorBrush 类型从SolidColorBrush 更改为Color,然后像这样使用它:
private async void ThemeManager_ThemeChanged(Utils.ThemeManager theme)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
((SolidColorBrush)Application.Current.Resources["BackgroundBrush"]).Color = theme.HighAccentColorBrush;
});
}