5

Wanting to get the color combobox (see image) behavior in my WPF ListView column. photo

Can someone help me get this started? I am comfortable with ListView binding but not sure how to implement this.

EDIT:

 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>

Tells me type provided must be an enum.

Best Answer I have found: How can I list colors in WPF with XAML?

Shloime Rosenblum
  • 927
  • 11
  • 26
markokstate
  • 923
  • 2
  • 14
  • 28
  • What is the problem? Create some collection of color-color name pairs, create the appropriate combobox `ItemTemplate` that shows some rectangle and TextBlock, then use the first collection as `ItemsSource` for the ComboBox. – Eugene Podskal Mar 25 '15 at 18:44
  • I want to use the System.Windows.Media.Colors named colors list. Meaning I don't want to make a custom enum list. How do I access this enum in the ODP? – markokstate Mar 25 '15 at 18:47
  • To achieve this you will have to use some Reflection - enumerate over the static properties with return type of `Color` and create pairs of (property name, property getter result). – Eugene Podskal Mar 25 '15 at 18:48
  • @markostate Colors is not an enum. It is a static class with a set of static properties for each color. – Eugene Podskal Mar 25 '15 at 18:54

2 Answers2

8

ComboBox with ItemTemplate

You will have to use ItemTemplate for you ComboBox items:

    <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>

Brush converter

Also, you will need a color to brush converter, because binding doesn't do it automatically:

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

Color name - color pair creation

And here is how you can create the color Name - color pairs (currently it is an instance method in the main Window class, but you can refactor it to some helper class):

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

Window code

And this is the window:

/// <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

Some code file:

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 object data provider:

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

XAML comboBox:

<ComboBox ItemsSource="{Binding ColorList}" ...
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • the long and hard way to achieve what you want without MVVM, a? – Dragos Stoica Mar 25 '15 at 19:18
  • 2
    @DragoshStoica I am not sure that I understand your sarcasm about MVVM. This answer is just a complete working solution that both demonstrates the concept and allows to run it, nothing more nothing less. If the need arises then it can be easily reworked to fit the desired design pattern and architectural preferences. – Eugene Podskal Mar 25 '15 at 19:26
  • I think this answer may work, but I am trying to assign the .ItemSource directly to the list. Looks like most of the pieces are here, what would I need to change in my main to allow that? – markokstate Mar 26 '15 at 14:35
  • @markokstate I have added the `ObjectDataProvider` variant. – Eugene Podskal Mar 26 '15 at 15:06
  • @EugenePodskal this most accurately answered my question with the use of the ObjectDataProvider. This was the most straight forward and least code required solution in my eyes. Thank you. – markokstate Mar 30 '15 at 15:37
1

Should be something like this :

 <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>

Where DisplayesText and Color (type of Brushes) are properties of an object lets say A and ItemSourceObs is ObservableCollection of type A

This approach is based on MVVM pattern

Using code behind working solution :

 <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>

And code behind :

public MainWindow()
    {
        InitializeComponent();
        ComboColor.ItemsSource = typeof(Colors).GetProperties();
    }
Dragos Stoica
  • 1,753
  • 1
  • 21
  • 42
  • Does this method work when the combobox is inside of the listview? – markokstate Mar 25 '15 at 20:02
  • It's not recognizing ComboColor when I have it embedded into my datatemplate of my viewcolumn definition. – markokstate Mar 25 '15 at 20:13
  • if you use datatemplate and you want to access a control by name is recommended to take look here and please mark the answer as solved: 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 Mar 25 '15 at 20:45
  • So then I need to loop through all ListViewItems and assign ComboColor.ItemsSource? – markokstate Mar 26 '15 at 14:24
  • yes. you need to find ComboColor by looping through ListViewItems and set itemsource. like you can see in the above link which I gave it. – Dragos Stoica Mar 26 '15 at 14:31