WPF ComboBox作为System.Windows.Media.Colors

5

我想在我的WPF ListView列中实现颜色下拉框(见图像)的行为。

photo

有人能帮助我开始吗?我对ListView绑定很熟悉,但不确定如何实现这个功能。

编辑:

 xmlns:System="clr-namespace:System;assembly=mscorlib"

<ObjectDataProvider MethodName="GetValues"
                    ObjectType="{x:Type System:Enum}"
                    x:Key="ColorList">
   <ObjectDataProvider.MethodParameters>
       <x:Type TypeName="Windows.Media.Color" />
   </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

告诉我提供的类型必须是枚举类型。 我找到的最佳答案:如何在WPF中使用XAML列出颜色?

问题是什么?创建一些颜色-颜色名称对的集合,创建适当的组合框“ItemTemplate”,显示一些矩形和TextBlock,然后使用第一个集合作为ComboBox的“ItemsSource”。 - Eugene Podskal
我想使用 System.Windows.Media.Colors 的命名颜色列表,意思是我不想创建自定义的枚举列表。我该如何在 ODP 中访问此枚举? - markokstate
为了实现这一点,您将需要使用一些反射 - 枚举具有返回类型为“Color”的静态属性,并创建(属性名称,属性getter结果)对。 - Eugene Podskal
@markostate Colors不是枚举。它是一个静态类,每个颜色都有一组静态属性。 - Eugene Podskal
2个回答

8

带ItemTemplate的ComboBox

您需要使用ItemTemplate来设置ComboBox的项目:

    <ComboBox ItemsSource="{Binding NamedColors}"
              xmlns:converters="clr-namespace:TestLab.WPF">
        <ComboBox.Resources>
            <converters:ColorToSolidBrushConverter x:Key="ColorToBrush"/>
        </ComboBox.Resources>
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Border BorderThickness="0" Height="20" Width="20" 
                            Background="{Binding Value, Converter={StaticResource ColorToBrush}}"/>
                    <TextBlock Text="{Binding Key}"/>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

画笔转换器

另外,您需要一个颜色到画笔的转换器,因为绑定不会自动完成这个操作:

public class ColorToSolidBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new SolidColorBrush((Color)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

颜色名称 - 颜色对创建

以下是如何创建颜色名称 - 颜色对(目前它是主窗口类中的实例方法,但您可以将其重构为一些辅助类):

    private IEnumerable<KeyValuePair<String, Color>> GetColors()
    {
        return typeof(Colors)
            .GetProperties()
            .Where(prop =>
                typeof(Color).IsAssignableFrom(prop.PropertyType))
            .Select(prop =>
                new KeyValuePair<String, Color>(prop.Name, (Color)prop.GetValue(null)));
    }

窗口代码

这是窗口:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.NamedColors = this.GetColors();

        this.DataContext = this;
    }

    public IEnumerable<KeyValuePair<String, Color>> NamedColors
    {
        get;
        private set;
    }
}

ObjectDataProvider

一个代码文件:

public namespace SomeNamespace 
{
    public static class ColorHelper
    {
        public static IEnumerable<KeyValuePair<String, Color>> GetColors()
        {
            return typeof(Colors)
                .GetProperties()
                .Where(prop =>
                    typeof(Color).IsAssignableFrom(prop.PropertyType))
                .Select(prop =>
                    new KeyValuePair<String, Color>(prop.Name, (Color)prop.GetValue(null)));
        }
    }
}

XAML对象数据提供程序:

...
xmlns:someNamespace="clr-namespace:SomeNamespace"
...
<ObjectDataProvider MethodName="GetColors"
                    ObjectType="{x:Type someNamespace.ColorHelper}"
                    x:Key="ColorList">
</ObjectDataProvider>

XAML组合框:

<ComboBox ItemsSource="{Binding ColorList}" ...

没有使用MVVM,实现你想要的东西的方法可能会很长且困难,对吧? - Dragos Stoica
2
@DragoshStoica 我不确定你对MVVM的讽刺是否理解。这个答案只是一个完整的工作解决方案,既演示了概念,又允许运行它,没有多余的东西。如果需要,它可以轻松地重新设计以适应所需的设计模式和架构偏好。 - Eugene Podskal
我认为这个答案可能有效,但我正在尝试直接将.ItemSource分配给列表。看起来大部分的代码都在这里了,我需要在我的主要代码中做哪些更改才能实现呢? - markokstate
@markokstate 我已经添加了ObjectDataProvider变量的版本。 - Eugene Podskal
@EugenePodskal,使用ObjectDataProvider最准确地回答了我的问题。在我看来,这是最直接和需要最少代码的解决方案。谢谢。 - markokstate

1
应该是这样的:

应该是这样的:

 <ComboBox ItemsSource="{Binding ItemSourceObs}">     
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle Fill="{Binding Color}" Height="10"  Width="10" />
                        <TextBlock Text="{Binding DisplayedText}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>    
        </ComboBox>

其中DisplayesText和Color(Brushes类型)是一个对象的属性,比如说A,而ItemSourceObs是类型为A的ObservableCollection

这种方法基于MVVM模式

使用代码后台的工作解决方案:

 <ComboBox x:Name="ComboColor" Width="50" Height="50"  >     
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>    
    </ComboBox>

代码后台:
public MainWindow()
    {
        InitializeComponent();
        ComboColor.ItemsSource = typeof(Colors).GetProperties();
    }

当ComboBox位于ListView内部时,这种方法是否有效? - markokstate
当我将ComboColor嵌入到我的视图列定义的数据模板中时,它无法识别。 - markokstate
如果您使用DataTemplate并且想要通过名称访问控件,则建议查看此处,并将答案标记为已解决:https://social.msdn.microsoft.com/Forums/vstudio/en-US/29ecc8ee-26ee-4331-8f97-35ff9d3e6886/how-to-access-items-in-a-datatemplate-for-wpf-listview?forum=wpf - Dragos Stoica
那么我需要循环遍历所有的ListViewItems并分配ComboColor.ItemsSource吗? - markokstate
是的。您需要通过循环遍历ListViewItems并设置itemsource来查找ComboColor,就像您可以在我提供的上面链接中看到的那样。 - Dragos Stoica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接