通过XAML将Windows强调文字颜色设置为WPF窗口背景,并收听强调文字颜色更改



我正在创建一个WPF项目,该项目使用windows 10 Accent颜色作为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()函数是从WndProcWM_DWMCOLORIZATIONCOLORCHANGED调用的,它可以帮助我将SystemAccentBrush设置为当前系统强调色,并且它非常有效。但是,当我将SystemAccentBrush设置为控件的背景时,它不会根据强调文字颜色更改而更改(但画笔颜色正在更改(。

以下是我用来设置SystemAccentBrush作为网格背景的代码:

<Grid x:Name="container" Background="{x:Static common:AccentColors.SystemAccentBrush}">
</Grid>

我认为问题与此有关:

{x:Static common:AccentColors.SystemAccentBrush}

因此,我尝试将其设置为动态源,如下所示:

{DynamicSource {x:Static common:AccentColors.SystemAccentBrush}}

然后背景消失了。

有什么办法可以克服这个问题吗

x:Static标记扩展用于静态引用,在运行时不会获取任何更改。

引用以符合公共语言规范(CLS(的方式定义的任何按值静态代码实体。

如果创建在运行时更改的静态属性,则必须使用绑定并实现类似于INotifyPropertyChangedPropertyChanged事件的静态等价物。自WPF4.5以来就支持此功能,并且有两种不同的方法来实现它

事件处理程序

按以下方式更改您的属性,并为您的属性创建一个事件SystemAccentBrushChanged。用nullEventArgs.EmptySystemAccentBrush的setter中引发事件。

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));
}

绑定静态属性

为了绑定静态属性以获取更改通知,您必须使用带有Path和圆括号的Binding来访问类成员。如果省略Path,XAML解析器和设计器将抛出并出错。

<Grid Background="{Binding Path=(common:AccentColors.SystemAccentBrush)}">

最后一点:尽管这种方式支持带有属性更改通知的静态绑定,但您可能需要考虑将静态类迁移到singleton。通过这种方式,您可以使SystemAccentBrush成为非静态属性,实现INotifyPropertyChanged并像往常一样绑定该属性,而无需任何特殊语法或自定义静态事件。

最新更新