Alexandru
Alexandru

Reputation: 12902

WPF: How do I programmatically style my ListView so that all rows have a certain background color and height?

I can't seem to wrap my head around something. Say I have the following logic in my code:

namespace WPFTesting
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        ObservableCollection<Message> messages = new ObservableCollection<Message>();

        public MainWindow()
        {
            InitializeComponent();
            messages.Add(new Message(DateTime.Now, "This is a test."));
            ListView listView = new ListView();
            GridView gridView = new GridView();
            listView.View = gridView;
            GridViewColumn timeStampColumn = new GridViewColumn();
            timeStampColumn.DisplayMemberBinding = new Binding("Date");
            GridViewColumnHeader timeStampHeader = new GridViewColumnHeader();
            timeStampHeader.Content = "Time";
            timeStampColumn.Header = timeStampHeader;
            gridView.Columns.Add(timeStampColumn);
            GridViewColumn messageColumn = new GridViewColumn();
            messageColumn.DisplayMemberBinding = new Binding("Text");
            GridViewColumnHeader messageHeader = new GridViewColumnHeader();
            messageHeader.Content = "Message";
            messageColumn.Header = messageHeader;
            gridView.Columns.Add(messageColumn);
            Binding binding = new Binding();
            binding.Source = messages;
            listView.SetBinding(ItemsControl.ItemsSourceProperty, binding);
            MainGrid.Children.Add(listView);
        }

        public class Message
        {

            public Message(DateTime aDate, String aText)
            {
                Date = aDate;
                Text = aText;
            }

            public DateTime Date { get; set; }
            public String Text { get; set; }
        }
    }
}

How do I programmatically style my ListView so that all rows have a certain background color and height? Note, I want to avoid doing a foreach loop on the ListView's Items list and setting each ListViewItem's properties, because this list may have very many items and this could be expensive. Instead, is there not some way to do this programmatically using the Style class, or perhaps some run-time logic?

Upvotes: 2

Views: 10195

Answers (2)

Wallstreet Programmer
Wallstreet Programmer

Reputation: 9677

GridView columns don't support styling, only header styling. Instead use a cell template to style column cells. This allows you to have different styles for different columns. For example you want currency columns to be right aligned but text columns to be left aligned.

This is how it looks using XAML for your Time column with red background style.

<GridViewColumn Header="Time">                            
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Date}">
                <TextBlock.Style>
                    <Style TargetType="{x:Type TextBlock}">
                        <Setter Property="Background" Value="Red" />
                    </Style>
                </TextBlock.Style>
            </TextBlock>
        </DataTemplate>
    </GridViewColumn.CellTemplate>
</GridViewColumn>

This can be done in code. FrameworkElementFactory class is a deprecated class which supports the creation of templates. The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class. Below code should be modified to allow for different styles depending on type of column.

public MainWindow()
{
    InitializeComponent();

    messages.Add(new Message(DateTime.Now, "This is a test."));

    ListView listView = new ListView();
    GridView gridView = new GridView();
    listView.View = gridView;

    gridView.Columns.Add(CreateGridViewColumn("Time", "Date"));
    gridView.Columns.Add(CreateGridViewColumn("Message","Text"));

    listView.SetBinding(ItemsControl.ItemsSourceProperty, new Binding() { Source = messages });

    MainGrid.Children.Add(listView);
}

private static GridViewColumn CreateGridViewColumn(string header, string bindingPath)
{
    GridViewColumn gridViewColumn = new GridViewColumn();
    gridViewColumn.Header = new GridViewColumnHeader() { Content = header };

    string xaml = @"
        <DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> 
            <TextBlock Text=""{Binding " + bindingPath + @"}""> 
                <TextBlock.Style>
                    <Style TargetType=""{x:Type TextBlock}"">
                        <Setter Property=""Background"" Value=""Red"" />
                    </Style>
                </TextBlock.Style>
            </TextBlock>
            </DataTemplate>";
    StringReader stringReader = new StringReader(xaml);
    XmlReader xmlReader = XmlReader.Create(stringReader);
    gridViewColumn.CellTemplate = XamlReader.Load(xmlReader) as DataTemplate;

    return gridViewColumn;
}

Upvotes: 2

Alexandru
Alexandru

Reputation: 12902

I figured it out. You can do it this way as an example:

Style style = new Style();
style.TargetType = typeof(ListViewItem);
style.Setters.Add(new Setter(ListViewItem.BackgroundProperty, Brushes.Pink));
listView.ItemContainerStyle = style;

Edit: You can also conditionally set a style on the ListView's Items using a trigger for certain values from your data set. I found this very useful, so this may help others as well:

DataTrigger trigger = new DataTrigger();
trigger.Binding = new Binding("Text");
trigger.Value = "This is a test.";
trigger.Setters.Add(new Setter(ListViewItem.BackgroundProperty, Brushes.Pink));
style.Triggers.Add(trigger);
listView.ItemContainerStyle = style;

The above code will only set the background of the row under the condition that the Text field is set to "This is a test."

Upvotes: 10

Related Questions