在 WPF 代码隐藏中,如何为每个单独的 ListBoxItem 设置背景颜色,其中颜色基于项目本身?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23302135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:38:36  来源:igfitidea点击:

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

wpfcolorsbackgroundcode-behindlistboxitem

提问by Torr

My end goal is to have a ListBoxshow me a list of colors, where the value of the background color is the color itself. Eventually, this ListBoxwill 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 stringis the friendly name and Coloris a custom class that only contains the Red, Green, Blue, and Hexvalues 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.

我的最终目标是向ListBox我展示一个颜色列表,其中背景颜色的值是颜色本身。最终,这ListBox将加载以前保存的颜色集合,但现在我只是想让它使用虚拟数据 - 我使用来自System.Windows.Media.Colors(的颜色填充的字典<string, Color>,其中string友好名称Color是自定义类仅包含RedGreenBlueHex为颜色值)。以这种方式设置是因为用户存储的颜色最终将只有一个名称(键)和 RGB/Hex 值。

I have no problem getting the names of the colors to show up in the ListBoxby settings its ItemsSourceto App.SavedColors.Keys(where SavedColorsis 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.

我可以毫无问题地将颜色的名称显示在ListBoxby 设置ItemsSourceApp.SavedColors.KeysSavedColors前面提到的字典在哪里)。我找到了一些答案,如果您知道自己想要什么颜色(即“绿色”,如果“严重性”或某事物等于 1),则可以根据属性解释如何执行此操作,但也没有绑定颜色的答案。

Using a solution I found while trying to research this, I was able to figure out how to almostmake it work. But it seems like this code just colors the backgrounds of allthe items, according to the color of the lastitem, 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;
}

回答by Dmitry

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.

您的代码的问题在于您分配了影响所有 ListBoxItems 的相同属性 ItemsContainerStyle。所以所有的项目都会有最后一个的颜色。

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.

但是作为 Peter Hansen 最好使用 XAML 来解决这个问题。例如,您可以编写一个转换器,将 ListBoxItem 中的数据转换为 SolidColorBrush。然后您可以将项目的背景绑定到其内容。

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:

XAML 将如下所示:

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