通过 XAML 将 Windows Accent Color 设置为 WPF 窗口背景并监听 Accent Color Change
Posted
技术标签:
【中文标题】通过 XAML 将 Windows Accent Color 设置为 WPF 窗口背景并监听 Accent Color Change【英文标题】:Setting Windows Accent Color as WPF Window Background through XAML and listen to Accent Color Change 【发布时间】:2021-03-17 04:57:25 【问题描述】:我正在创建一个 WPF 项目,它使用 windows 10 强调色作为我的 WPF 主窗口的背景。我能够使用GetImmersiveUserColorSetPreference()
、GetImmersiveColorTypeFromName()
和GetImmersiveColorFromColorSetEx()
获得窗口的强调色,并且可以将它用作我的窗口背景。但问题是我无法在更改强调色时自动更改背景(我必须重新启动才能更改背景)。
这是我使用的代码:
AccentColors.cs
public static class AccentColors
private static Brush systemAccentBrush;
static AccentColors()
InitializeBrushes();
public static void InitializeBrushes()
SystemAccentBrush = CreateBrush(GetColorByTypeName("ImmersiveSystemAccent"));
public static Color GetColorByTypeName(string name)
var colorSet = NativeMethods.GetImmersiveUserColorSetPreference(false, false);
var colorType = NativeMethods.GetImmersiveColorTypeFromName(name);
var rawColor = NativeMethods.GetImmersiveColorFromColorSetEx(colorSet, colorType, false, 0);
var bytes = BitConverter.GetBytes(rawColor);
return Color.FromArgb(bytes[3], bytes[0], bytes[1], bytes[2]);
private static Brush CreateBrush(Color color)
var brush = new SolidColorBrush(color);
return brush;
#region Brushes
public static Brush SystemAccentBrush
get
return systemAccentBrush;
private set
if (!object.Equals(systemAccentBrush, value))
systemAccentBrush = value;
#endregion
InitializeBrushes()
函数是从 WndProc
WM_DWMCOLORIZATIONCOLORCHANGED
调用的,这有助于我将 SystemAccentBrush
设置为当前系统 Accent Color 并且它工作得很好。但是当我设置SystemAccentBrush
作为控件的背景,它不会根据 Accent Color 更改(但画笔颜色正在更改)而更改。
这是我用来将 SystemAccentBrush 设置为 Grid 的背景的代码:
<Grid x:Name="container" Background="x:Static common:AccentColors.SystemAccentBrush">
</Grid>
我认为问题与此有关:
x:Static common:AccentColors.SystemAccentBrush
所以我尝试将其设置为动态源,如下所示:
DynamicSource x:Static common:AccentColors.SystemAccentBrush
然后背景消失了。
有什么办法可以解决这个问题吗?
【问题讨论】:
【参考方案1】:x:Static
markup extension 用于静态引用,不会在运行时获取任何更改。
引用以符合公共语言规范 (CLS) 的方式定义的任何静态按值代码实体。
如果您创建在运行时更改的静态属性,则必须使用绑定并实现类似于INotifyPropertyChanged
的PropertyChanged
事件的静态等效项。从 WPF 4.5 开始支持此功能,并且有 two different ways 来实现它。
事件处理程序
如下更改您的属性并为您的属性创建一个事件SystemAccentBrushChanged
。使用null
和EventArgs.Empty
在SystemAccentBrush
的设置器中引发事件。
private static Brush systemAccentBrush;
public static Brush SystemAccentBrush
get => systemAccentBrush;
private set
if (Equals(systemAccentBrush, value))
return;
systemAccentBrush = value;
SystemAccentBrushChanged?.Invoke(null, EventArgs.Empty);
public static event EventHandler SystemAccentBrushChanged;
静态属性改变事件
如下更改您的属性并创建一个事件StaticPropertyChanged
并使用已更改的属性名称引发它。此事件可以与不同的属性一起使用。
private static Brush systemAccentBrush;
public static Brush SystemAccentBrush
get => systemAccentBrush;
private set
if (Equals(systemAccentBrush, value))
return;
systemAccentBrush = value;
OnStaticPropertyChanged();
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
private static void OnStaticPropertyChanged([CallerMemberName] string propertyName = null)
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
绑定静态属性
为了绑定静态属性以获取更改通知,您必须使用Binding
和Path
和括号来访问类成员。如果省略Path
,XAML 解析器和设计器将抛出错误。
<Grid Background="Binding Path=(common:AccentColors.SystemAccentBrush)">
最后一点说明:虽然这种方式支持带有属性更改通知的静态绑定,但您可能需要考虑将静态类迁移到单例。这样,您可以将SystemAccentBrush
设为非静态属性,实现INotifyPropertyChanged
并照常绑定该属性,无需任何特殊语法或自定义静态事件。
【讨论】:
非常感谢它运行良好,您的回答非常容易理解。你绝对值得一票。以上是关于通过 XAML 将 Windows Accent Color 设置为 WPF 窗口背景并监听 Accent Color Change的主要内容,如果未能解决你的问题,请参考以下文章
在通用 Windows 应用 (XAML) 中启用后退/前进和刷新手势
用于设计 Windows 10 应用程序的 GUI?还是仅通过 XAML?
如何将 Windows 商店中的 Windows Phone 应用程序(8.1 XAML)迁移到 8.1 Silverlight?
在 App.xaml 中添加按钮并以编程方式将其添加到其他 xaml 页面 Windows 运行时应用