In WPF code-behind, how do I set the background color for each individual ListBoxItem where the color is based on the item itself?

StackOverflow https://stackoverflow.com/questions/23302135

Question

My end goal is to have a ListBox show me a list of colors, where the value of the background color is the color itself. Eventually, this ListBox will load a previously saved collection of colors, but for now I'm just trying to get it to work with dummy data - a dictionary I filled up using the colors from System.Windows.Media.Colors (<string, Color>, where string is the friendly name and Color is a custom class that only contains the Red, Green, Blue, and Hex values for the color). It's set up this way because the user-stored colors will eventually just have a name (the key), and RGB/Hex values.

I have no problem getting the names of the colors to show up in the ListBox by settings its ItemsSource to App.SavedColors.Keys (where SavedColors is the previously mentioned dictionary). And I found some answers that could explain how to do it based off of a property if you knew what colors you wanted (i.e. "green" if "severity" or something was equal to 1), but nothing for binding the color as well.

Using a solution I found while trying to research this, I was able to figure out how to almost make it work. But it seems like this code just colors the backgrounds of all the items, according to the color of the last item, so I imagine this just changes the overall background color every time a new row is created. How do I keep each iteration from overwriting the previous background?

The closest code I've been able to use so far:

//Bind the saved colors.
ListBox_SavedColors.ItemsSource = App.SavedColors.Keys;

//Color the backgrounds.
for (int i = 0; i < ListBox_SavedColors.Items.Count; i++)
{
    //Create the blank style.
    Style styleBackground = new System.Windows.Style();
    styleBackground.TargetType = typeof(ListBoxItem);

    //Get the color and store it in a brush.
    Color color = App.SavedColors[ListBox_SavedColors.Items[i].ToString()];
    SolidColorBrush backgroundBrush = new SolidColorBrush();
    backgroundBrush.Color = System.Windows.Media.Color.FromRgb(color.Red, color.Green, color.Blue);

    //Create a background setter and add the brush to it.
    styleBackground.Setters.Add(new Setter
    {
        Property = ListBoxItem.BackgroundProperty,
        Value = backgroundBrush
    });

    ListBox_SavedColors.ItemContainerStyle = styleBackground;
}
Was it helpful?

Solution

The problem with your code is that you assign the same property ItemsContainerStyle that impacts all of the ListBoxItems. So all of the items will have the color of the last one.

Your code should directly assign the Background of the items.

for (int i = 0; i < ListBox_SavedColors.Items.Count; i++)
{
    //Get the color and store it in a brush.
    Color color = App.SavedColors[ListBox_SavedColors.Items[i].ToString()];
    SolidColorBrush backgroundBrush = new SolidColorBrush(color);

    ListBoxItem item = ListBox_SavedColors.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
    item.Background = backgroundBrush;
}

But as Peter Hansen it is better to use a XAML to solve this problem. For exemple you can write a converter that will convert the data in the ListBoxItem into a SolidColorBrush. Then you can bind the background of an item to its content.

public class ListBoxItemColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new SolidColorBrush(App.SavedColors[value.ToString()]);
    }

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

XAML will look like this:

<ListBox x:Name="MyList">
    <ListBox.Resources>
        <local:ListBoxItemColorConverter x:Key="ListBoxItemColorConverter"/>
    </ListBox.Resources>
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" Value="{Binding Converter={StaticResource ListBoxItemColorConverter}}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top