从 C# 更新 ThemeResources?
Update ThemeResources from c#?
我有一个分析图像的空白,提取两种主色,并替换 "SystemControlForegroundAccentBrush" 和 "SystemControlHighlightAccentBrush",我在 App.xaml 中覆盖了它们。它运行良好,只是需要一些时间来分析图像,所以一旦我页面中的所有控件都已加载,它就会更改颜色。
结果,它们保留了旧的强调色。我怎样才能让它们动态绑定到 ThemeRessource?
这是我的 app.xaml:
<Application.Resources>
<ResourceDictionary x:Name="resdic">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="SystemControlForegroundAccentBrush"/>
<SolidColorBrush x:Key="SystemControlHighlightAccentBrush"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
这是 ColorExtractor.cs class 中改变颜色的(非常简化的)部分:
public async static void Analyse()
{
Application.Current.Resources["SystemControlForegroundAccentBrush"] = new SolidColorBrush(color);
Application.Current.Resources["SystemControlHighlightAccentBrush"] = new SolidColorBrush(color2);
}
我在 Page.xaml 中有一堆控件,它们的前景设置如下:
<TextBlock Foreground="{ThemeResource SystemControlForegroundAccentBrush]"/>
我在 Page.xaml.cs 中调用 ColorExtractor.Analyse()
(在 OnNavigatedTo 事件中)。我总是可以创建一个在设置颜色后触发的事件,但我需要找到一种方法来更新我页面中所有控件的颜色。
您可以看看模板 10 是如何进行主题更改的,但在他们的例子中,他们提前在资源字典中定义了两个不同的主题。您可以在 repo on Github 中找到他们的代码,但这里有一些使用的代码:
(Window.Current.Content as FrameworkElement).RequestedTheme = value.ToElementTheme();
Views.Shell.SetRequestedTheme(value, UseBackgroundChecked);
来自here
public static void SetRequestedTheme(ApplicationTheme theme, bool UseBackgroundChecked)
{
WindowWrapper.Current().Dispatcher.Dispatch(() =>
{
(Window.Current.Content as FrameworkElement).RequestedTheme = theme.ToElementTheme();
ParseStyleforThemes(theme);
HamburgerMenu.NavButtonCheckedForeground = NavButtonCheckedForegroundBrush;
HamburgerMenu.NavButtonCheckedBackground = (UseBackgroundChecked) ?
NavButtonCheckedBackgroundBrush : NavButtonBackgroundBrush;
HamburgerMenu.NavButtonCheckedIndicatorBrush = (UseBackgroundChecked) ?
Colors.Transparent.ToSolidColorBrush() : NavButtonCheckedIndicatorBrush;
HamburgerMenu.SecondarySeparator = SecondarySeparatorBrush;
List<HamburgerButtonInfo> NavButtons = HamburgerMenu.PrimaryButtons.ToList();
NavButtons.InsertRange(NavButtons.Count, HamburgerMenu.SecondaryButtons.ToList());
List<HamburgerMenu.InfoElement> LoadedNavButtons = new List<HamburgerMenu.InfoElement>();
foreach (var hbi in NavButtons)
{
StackPanel sp = hbi.Content as StackPanel;
if (hbi.ButtonType == HamburgerButtonInfo.ButtonTypes.Literal) continue;
ToggleButton tBtn = sp.Parent as ToggleButton;
Button btn = sp.Parent as Button;
if (tBtn != null)
{
var button = new HamburgerMenu.InfoElement(tBtn);
LoadedNavButtons.Add(button);
}
else if (btn != null)
{
var button = new HamburgerMenu.InfoElement(btn);
LoadedNavButtons.Add(button);
continue;
}
else
{
continue;
}
Rectangle indicator = tBtn.FirstChild<Rectangle>();
indicator.Visibility = ((!hbi.IsChecked ?? false)) ? Visibility.Collapsed : Visibility.Visible;
if (!hbi.IsChecked ?? false) continue;
ContentPresenter cp = tBtn.FirstAncestor<ContentPresenter>();
cp.Background = NavButtonCheckedBackgroundBrush;
cp.Foreground = NavButtonCheckedForegroundBrush;
}
LoadedNavButtons.ForEach(x => x.RefreshVisualState());
});
}
来自here
I've got a void that analyses an image, extracts two dominant colors, and replaces "SystemControlForegroundAccentBrush" and "SystemControlHighlightAccentBrush", that I'm overriding in App.xaml.
首先,我认为您在 app.xaml 中的代码无法覆盖 ThemeResource
,并且您在页面中使用了此 Brush
,如下所示:
<TextBlock Foreground="{ThemeResource SystemControlForegroundAccentBrush}" Text="Hello World!" FontSize="50" />
如果您在 SystemControlForegroundAccentBrush
上按 "F12",您实际上可以在 "generic.xaml" 文件中找到该资源。
现在假设你的 ColorExtractor.cs
class 工作正常并且 ColorExtractor.Analyse()
可以覆盖这两个画笔的颜色,并且页面中有许多控件使用这两个资源,刷新此处页面可以解决您的问题。
但是我觉得这个操作还是不要放在OnNavagateTo
事件或者Page.Loaded
事件里面比较好,UWP里面没有刷新的方法,我们使用再次导航到这个页面刷新,所以如果将此操作放在 OnNavagateTo
事件或 Page.Loaded
事件中,每次导航到此页面时,资源将被覆盖并再次导航。所以我把这个操作放在一个 Button click 事件中,像这样:
public bool Reload()
{
return Reload(null);
}
private bool Reload(object param)
{
Type type = this.Frame.CurrentSourcePageType;
if (this.Frame.BackStack.Any())
{
type = this.Frame.BackStack.Last().SourcePageType;
param = this.Frame.BackStack.Last().Parameter;
}
try { return this.Frame.Navigate(type, param); }
finally
{
this.Frame.BackStack.Remove(this.Frame.BackStack.Last());
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ColorExtractor.Analyse();
Reload();
}
最终,我决定在ColorExtractor.cs中创建一个事件:
public static event EventHandler Analysed;
public async static void Analyse(BitmapImage poster)
{
//Analyse colors
Analysed(null, null);
}
然后,在我的 MainPage.xaml.cs 上:
ColorExtractor.Analyse(bmp);
ColorExtractor.Analysed += (sender, EventArgs) =>
{
//Set Page foreground color, as a lot of controls are dynamically binded to their parent's foreground brush.
//If a control isn't automatically binded, all I have to do is say: Foreground="{Binding Foreground, ElementName=page}"
page.Foreground = Application.Current.Resources["SystemControlForegroundAccentBrush"] as SolidColorBrush;
page.BorderBrush = Application.Current.Resources["SystemControlHighlightAccentBrush"] as SolidColorBrush;
//Reload any custom user control that sets it's children's color when it's loaded.
backdrop.UserControl_Loaded(null, null);
};
所以我实际上并没有直接将我的控件绑定到 ForegroundAccentBrush,但这不需要重新导航到页面就可以工作。
我有一个分析图像的空白,提取两种主色,并替换 "SystemControlForegroundAccentBrush" 和 "SystemControlHighlightAccentBrush",我在 App.xaml 中覆盖了它们。它运行良好,只是需要一些时间来分析图像,所以一旦我页面中的所有控件都已加载,它就会更改颜色。 结果,它们保留了旧的强调色。我怎样才能让它们动态绑定到 ThemeRessource?
这是我的 app.xaml:
<Application.Resources>
<ResourceDictionary x:Name="resdic">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="SystemControlForegroundAccentBrush"/>
<SolidColorBrush x:Key="SystemControlHighlightAccentBrush"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
这是 ColorExtractor.cs class 中改变颜色的(非常简化的)部分:
public async static void Analyse()
{
Application.Current.Resources["SystemControlForegroundAccentBrush"] = new SolidColorBrush(color);
Application.Current.Resources["SystemControlHighlightAccentBrush"] = new SolidColorBrush(color2);
}
我在 Page.xaml 中有一堆控件,它们的前景设置如下:
<TextBlock Foreground="{ThemeResource SystemControlForegroundAccentBrush]"/>
我在 Page.xaml.cs 中调用 ColorExtractor.Analyse()
(在 OnNavigatedTo 事件中)。我总是可以创建一个在设置颜色后触发的事件,但我需要找到一种方法来更新我页面中所有控件的颜色。
您可以看看模板 10 是如何进行主题更改的,但在他们的例子中,他们提前在资源字典中定义了两个不同的主题。您可以在 repo on Github 中找到他们的代码,但这里有一些使用的代码:
(Window.Current.Content as FrameworkElement).RequestedTheme = value.ToElementTheme();
Views.Shell.SetRequestedTheme(value, UseBackgroundChecked);
来自here
public static void SetRequestedTheme(ApplicationTheme theme, bool UseBackgroundChecked)
{
WindowWrapper.Current().Dispatcher.Dispatch(() =>
{
(Window.Current.Content as FrameworkElement).RequestedTheme = theme.ToElementTheme();
ParseStyleforThemes(theme);
HamburgerMenu.NavButtonCheckedForeground = NavButtonCheckedForegroundBrush;
HamburgerMenu.NavButtonCheckedBackground = (UseBackgroundChecked) ?
NavButtonCheckedBackgroundBrush : NavButtonBackgroundBrush;
HamburgerMenu.NavButtonCheckedIndicatorBrush = (UseBackgroundChecked) ?
Colors.Transparent.ToSolidColorBrush() : NavButtonCheckedIndicatorBrush;
HamburgerMenu.SecondarySeparator = SecondarySeparatorBrush;
List<HamburgerButtonInfo> NavButtons = HamburgerMenu.PrimaryButtons.ToList();
NavButtons.InsertRange(NavButtons.Count, HamburgerMenu.SecondaryButtons.ToList());
List<HamburgerMenu.InfoElement> LoadedNavButtons = new List<HamburgerMenu.InfoElement>();
foreach (var hbi in NavButtons)
{
StackPanel sp = hbi.Content as StackPanel;
if (hbi.ButtonType == HamburgerButtonInfo.ButtonTypes.Literal) continue;
ToggleButton tBtn = sp.Parent as ToggleButton;
Button btn = sp.Parent as Button;
if (tBtn != null)
{
var button = new HamburgerMenu.InfoElement(tBtn);
LoadedNavButtons.Add(button);
}
else if (btn != null)
{
var button = new HamburgerMenu.InfoElement(btn);
LoadedNavButtons.Add(button);
continue;
}
else
{
continue;
}
Rectangle indicator = tBtn.FirstChild<Rectangle>();
indicator.Visibility = ((!hbi.IsChecked ?? false)) ? Visibility.Collapsed : Visibility.Visible;
if (!hbi.IsChecked ?? false) continue;
ContentPresenter cp = tBtn.FirstAncestor<ContentPresenter>();
cp.Background = NavButtonCheckedBackgroundBrush;
cp.Foreground = NavButtonCheckedForegroundBrush;
}
LoadedNavButtons.ForEach(x => x.RefreshVisualState());
});
}
来自here
I've got a void that analyses an image, extracts two dominant colors, and replaces "SystemControlForegroundAccentBrush" and "SystemControlHighlightAccentBrush", that I'm overriding in App.xaml.
首先,我认为您在 app.xaml 中的代码无法覆盖 ThemeResource
,并且您在页面中使用了此 Brush
,如下所示:
<TextBlock Foreground="{ThemeResource SystemControlForegroundAccentBrush}" Text="Hello World!" FontSize="50" />
如果您在 SystemControlForegroundAccentBrush
上按 "F12",您实际上可以在 "generic.xaml" 文件中找到该资源。
现在假设你的 ColorExtractor.cs
class 工作正常并且 ColorExtractor.Analyse()
可以覆盖这两个画笔的颜色,并且页面中有许多控件使用这两个资源,刷新此处页面可以解决您的问题。
但是我觉得这个操作还是不要放在OnNavagateTo
事件或者Page.Loaded
事件里面比较好,UWP里面没有刷新的方法,我们使用再次导航到这个页面刷新,所以如果将此操作放在 OnNavagateTo
事件或 Page.Loaded
事件中,每次导航到此页面时,资源将被覆盖并再次导航。所以我把这个操作放在一个 Button click 事件中,像这样:
public bool Reload()
{
return Reload(null);
}
private bool Reload(object param)
{
Type type = this.Frame.CurrentSourcePageType;
if (this.Frame.BackStack.Any())
{
type = this.Frame.BackStack.Last().SourcePageType;
param = this.Frame.BackStack.Last().Parameter;
}
try { return this.Frame.Navigate(type, param); }
finally
{
this.Frame.BackStack.Remove(this.Frame.BackStack.Last());
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ColorExtractor.Analyse();
Reload();
}
最终,我决定在ColorExtractor.cs中创建一个事件:
public static event EventHandler Analysed;
public async static void Analyse(BitmapImage poster)
{
//Analyse colors
Analysed(null, null);
}
然后,在我的 MainPage.xaml.cs 上:
ColorExtractor.Analyse(bmp);
ColorExtractor.Analysed += (sender, EventArgs) =>
{
//Set Page foreground color, as a lot of controls are dynamically binded to their parent's foreground brush.
//If a control isn't automatically binded, all I have to do is say: Foreground="{Binding Foreground, ElementName=page}"
page.Foreground = Application.Current.Resources["SystemControlForegroundAccentBrush"] as SolidColorBrush;
page.BorderBrush = Application.Current.Resources["SystemControlHighlightAccentBrush"] as SolidColorBrush;
//Reload any custom user control that sets it's children's color when it's loaded.
backdrop.UserControl_Loaded(null, null);
};
所以我实际上并没有直接将我的控件绑定到 ForegroundAccentBrush,但这不需要重新导航到页面就可以工作。