您遇到的最大问题是您尝试使用为 Winforms API 编写的代码示例,即使您使用的是 WPF API。为了将来参考,您确实需要更加小心地识别您在网上找到的教程和其他资源的上下文,以确保它们确实适用于您的场景。
碰巧的是,我们已经有很多关于 Stack Overflow 的相关问题:
WPF ComboBox as System.Windows.Media.Colors>
WPF - Bind ComboBox Item Foreground to Its Value
Very simple color picker made of combobox
这些都可能对你有用,但都是基于这个问题的答案:
How can I list colors in WPF with XAML?
最初只是显示颜色的名称,因此采用了捷径,在 XAML 中使用 <ObjectDataProvider/> 元素。这导致需要在其他问题中使用转换器,将string 值或PropertyInfo 实例转换为适当的颜色或画笔。
事实上,如果您的代码已经编写为使用某种类型的 MVVM 方法,特别是因为您已经编写了代码隐藏来从 Colors 类型中检索颜色值,或者至少尝试过(一个代码中的问题之一是您使用的是 Winforms Color 类型而不是 WPF Colors 类型......再次,在 Winforms 中运行良好,但 WPF API 更严格地遵循代码分析/FxCop 规则,并且命名颜色在 Colors 类型中),坚持使用它并提供可以绑定的直接视图模型数据结构是有意义的。
在这种方法中,不是提供项目绘制的程序实现,而是在 XAML 中提供一个声明性实现描述每个项目应该是什么样子。
这是一个例子……
首先,一些简单的视图模型数据结构:
// Very simple container class
class ColorViewModel
{
public Brush Brush { get; }
public string Name { get; }
public ColorViewModel(Brush brush, string name)
{
Brush = brush;
Name = name;
}
}
// Main view model, acts as the data context for the window
class MainViewModel : INotifyPropertyChanged
{
public IReadOnlyList<ColorViewModel> Colors { get; }
private Brush _selectedColor;
public Brush SelectedColor
{
get { return _selectedColor; }
set { _UpdateField(ref _selectedColor, value); }
}
public MainViewModel()
{
Colors = typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public)
.Select(p => new ColorViewModel(new SolidColorBrush((Color)p.GetValue(null)), p.Name))
.ToList().AsReadOnly();
}
public event PropertyChangedEventHandler PropertyChanged;
private void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
有了这些,XAML 就很简单了:
<Window x:Class="TestSO47850587ColorComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO47850587ColorComboBox"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:MainViewModel/>
</Window.DataContext>
<StackPanel>
<ComboBox Width="100" ItemsSource="{Binding Colors}"
HorizontalAlignment="Left" Grid.IsSharedSizeScope="True"
SelectedValuePath="Brush" SelectedValue="{Binding SelectedColor}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type l:ColorViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ComboBoxItem"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Background="{Binding Brush}" HorizontalAlignment="Stretch"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Rectangle HorizontalAlignment="Stretch" Height="24" Fill="{Binding SelectedColor}"/>
</StackPanel>
</Window>
上面显示颜色名称,使用实际颜色作为背景。如果您真正想要的只是一个矩形,那么您可以将<TextBlock/> 元素替换为<Rectangle/> 元素,绑定到它的Fill 属性。当然,您可以实现其他视觉效果,例如带边距的矩形。只需根据需要配置数据模板即可。
这里的要点是您应该接受定义良好 WPF 编程的数据绑定方法,并且您绝对应该不将 Winforms 代码示例误认为 WPF。 :)