Search code examples
c#wpflistviewlistviewitem

Zebra-Color-Style ListViewItem rows GROUPED by text in 2nd column


I want to color the background of a group of ListViewItems so I can see the grouping by the values in the 2nd column.

Here is a sample C# code:

class Bla
{
    public int col1 { get; set; }
    public int col2 { get; set; }
}

public partial class MainWindow : Window
{
    ObservableCollection<Bla> obsListItems = new ObservableCollection<Bla>();

    public MainWindow()
    {
        InitializeComponent();

        obsListItems.Add(new Bla
        {
            col1 = 1, col2 = 111
        });
        obsListItems.Add(new Bla
        {
            col1 = 2, col2 = 111
        });
        obsListItems.Add(new Bla
        {
            col1 = 3, col2 = 222
        });
        obsListItems.Add(new Bla
        {
            col1 = 4, col2 = 333
        });
        obsListItems.Add(new Bla
        {
            col1 = 5, col2 = 333
        });
        obsListItems.Add(new Bla
        {
            col1 = 6, col2 = 444
        });

        obsListItems.Add(new Bla
        {
            col1 = 7, col2 = 444
        });

        Zebra.ItemsSource = obsListItems;

        this.DataContext = this;
    }
}

As you can see, the values of col1 are unique, while col2 has repeating numbers.

Where col2 has values like 111 and 333, the backgroundcolors should become - let's say - green while the rest keeps their background color.

By the way: Of course these are mockups...in the future use, there'll be loads of more ListViewItems with different values, straight from a database and ordered by the values of the 2nd column.

And here's my WPF control:

<ListView x:Name="Zebra"
              ItemsSource="{Binding Path=obsListItems}"
              SelectionMode="Single" Background="#FFC8F0F1" FontSize="16" Margin="0,0,0,10">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Column 1"
                                        DisplayMemberBinding="{Binding col1}"
                                        Width="70" />
                <GridViewColumn Header="Column 2"
                                        DisplayMemberBinding="{Binding col2}"
                                        Width="90" />
            </GridView>
        </ListView.View>
    </ListView>

@offtopic: Once I remove this line:

Zebra.ItemsSource = obsListItems;

it's not working anymore. I thought using ItemsSource="{Binding Path=obsListItems}" would work with the usage of this.Datacontext = this. Anyone know why?


Solution

  • Anyone know why?

    You can only bind to public properties:

    public ObservableCollection<Bla> obsListItems { get; } new ObservableCollection<Bla>();
    

    Regarding the "zebra" colouring you should be able to accomplish this with a converter. Please refer to the following code sample:

    namespace WpfApplication1
    {
        public class ColorConverter : IValueConverter
        {
            private static List<System.Windows.Media.Brush> _brushesToChooseFrom = new List<System.Windows.Media.Brush>()
            {
                System.Windows.Media.Brushes.Green,
                System.Windows.Media.Brushes.Red,
                System.Windows.Media.Brushes.Violet,
                System.Windows.Media.Brushes.Yellow
            };
            private Dictionary<int, System.Windows.Media.Brush> _usedBrushes = new Dictionary<int, System.Windows.Media.Brush>();
            private int index = 0;
    
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                int col2 = (int)value;
                if(!_usedBrushes.ContainsKey(col2))
                {
                    System.Windows.Media.Brush brush = _brushesToChooseFrom[index++];
                    if (index == _brushesToChooseFrom.Count)
                        index = 0;
                    _usedBrushes.Add(col2, brush);
                }
    
                return _usedBrushes[col2];
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    <ListView x:Name="Zebra"
                  ItemsSource="{Binding Path=obsListItems}"
                  SelectionMode="Single" Background="#FFC8F0F1" FontSize="16" Margin="0,0,0,10"
                  xmlns:local="clr-namespace:WpfApplication1">
        <ListView.Resources>
            <local:ColorConverter x:Key="conv" />
        </ListView.Resources>
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Background" Value="{Binding col2, Converter={StaticResource conv}}" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Column 1"
                                            DisplayMemberBinding="{Binding col1}"
                                            Width="70" />
                <GridViewColumn Header="Column 2"
                                            DisplayMemberBinding="{Binding col2}"
                                            Width="90" />
            </GridView>
        </ListView.View>
    </ListView>
    

    enter image description here