我正在创建一个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()
函数是从WndProc
WM_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(的方式定义的任何按值静态代码实体。
如果创建在运行时更改的静态属性,则必须使用绑定并实现类似于INotifyPropertyChanged
的PropertyChanged
事件的静态等价物。自WPF4.5以来就支持此功能,并且有两种不同的方法来实现它
事件处理程序
按以下方式更改您的属性,并为您的属性创建一个事件SystemAccentBrushChanged
。用null
和EventArgs.Empty
在SystemAccentBrush
的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
并像往常一样绑定该属性,而无需任何特殊语法或自定义静态事件。