在不扩展或设置模板的情况下修复 WPF ComboBox 颜色






2.33/5 (2投票s)
本文演示了一种非常简单的技术,可用于轻松修改标准的 Windows Presentation Foundation 控件,而无需创建扩展类或使用数据模板。
引言
如果您使用过 WPF 并使用了非标准配色方案,您可能会遇到 ComboBox 或其他 WPF 控件的问题。我使用的是深色配色方案,文字为白色。但是,我的应用程序中的 ComboBox 忽略了样式中的前景色设置。我唯一能让 ComboBox 前景色改变的方法是为每个 ComboBox 显式设置它。WPF 中的 ComboBox 样式已损坏。
我尝试了不同的技术来解决这个问题,但所有这些都需要比我喜欢的更多的代码。
- 第一次尝试:**扩展
ComboBox
** 类,使用隐藏前景色属性并手动设置它们的自定义类。这可行,但它要求我在 XAML 代码和样式中的TargetType
中使用不同的类名。 - 第二次尝试:创建一个包含
ComboBox
并手动设置颜色的**数据模板**。这不起作用,因为数据模板的前景色从未设置。 - 最终尝试:监听
Foreground
**依赖属性的Changed
事件**(实际上是一个回调),并在那里修复颜色。**这有效了!**而且它不需要更改任何 ComboBox 声明。
示例
第一个组合框没有更改前景色,而第二组是正确的。
下拉菜单的背景颜色仍然是白色。
下拉菜单的背景颜色与背景颜色匹配。
Using the Code
以下是完成所有工作的关键类
public static class ComboBoxFix
{
private static bool _isInitialized = false;
/// <summary>
/// Initialize must be called
/// before any Combo boxes are created
/// </summary>
public static void Initialize()
{
if( !_isInitialized )
{
// Registed the callback methods
// when the properties change on a ComboBox class
ComboBox.BackgroundProperty.OverrideMetadata(
typeof( ComboBox ),
new FrameworkPropertyMetadata( OnBackgroundChanged ) );
ComboBox.ForegroundProperty.OverrideMetadata(
typeof( ComboBox ),
new FrameworkPropertyMetadata( OnForegroundChanged ) );
_isInitialized = true;
}
}
private static void OnBackgroundChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e )
{
// Set the drop down background color to match the background
SetDropDownBackground( d as ComboBox );
}
private static void OnForegroundChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e )
{
// Manually set the foreground (to overcome bug)
// Apparently the ComboBox does not listen
// when the Foreground DepencyProperty
// is changed and therefore does not
// update itself unless the value is changed
// through the Foreground .net property
(d as ComboBox).Foreground = e.NewValue as Brush;
}
private static void SetDropDownBackground( ComboBox comboBox )
{
// The drop down control uses
// the WindowBrush to paint its background
// By overriding that Brush (just for this control)
if( comboBox.Resources.Contains( SystemColors.WindowBrushKey ) )
{
comboBox.Resources.Remove( SystemColors.WindowBrushKey );
}
comboBox.Resources.Add(
SystemColors.WindowBrushKey, comboBox.Background );
}
}
必须在创建任何 ComboBox
之前调用 Intialize
方法。将 ComboBoxFix.Iniatilize()
调用放在主窗口构造函数的首行是最佳位置。
关注点
依赖属性系统非常强大。只需少量代码,就可以注册到包含该属性的特定类型的所有对象的 Changed
事件。
但是,它比标准的 .NET 属性更复杂。重要的是要记住,WPF 绑定、动画等直接设置依赖属性。它们不会通过 .NET 属性 setter。
似乎此问题的根源与此差异有关。
因此,如果您创建任何依赖属性,请记住通过在属性元数据中注册回调方法来处理该值的更改。