locked
How to color a list box item at run time RRS feed

  • Question

  • I do not want to change colors in a selected or a highlighted item.  I want to color foreground on any item based on a program condition.

    IN windows forms I could change the drawmode property to ownerdrawfixed and then override the listbox rendering event and paint the item based on condition.

    I don not find such a property in the WPF listbox.  Is there a different way to do this?


    NR
    Friday, April 30, 2010 2:37 AM

Answers

  • Hi NR,

    one of the classic scenarios for a simple converter. Here's a sample:

     

    <Window x:Class="WpfTests.ListBox_FieldValueToForegroundConverter"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTests"
        Title="ListBox_FieldValueToForegroundConverter" Height="300" Width="300">
      <ListBox Margin="5" ItemsSource="{Binding TheItems}" >
       <ListBox.Resources>
         <local:StringToForegroundConverter x:Key="ForegroundConverter"/>
       </ListBox.Resources>
       <ListBox.ItemTemplate>
         <DataTemplate>
          <TextBlock Text="{Binding}"
                Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
                Margin="2"/>
         </DataTemplate>
       </ListBox.ItemTemplate>
      </ListBox>
    </Window>
    

     

    Code-behind:

     

    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfTests
    {
      public partial class ListBox_FieldValueToForegroundConverter : Window
      {
       //The list the ListBox binds to
       public List<string> TheItems { get; set; }
    
       public ListBox_FieldValueToForegroundConverter()
       {
         InitializeComponent();
    
         //Build a list to bind to
         TheItems = new List<string>();
         for (int i = 1; i < 50; i++)
          TheItems.Add("Item #" + i.ToString());
    
         //Change a couple of items to start with "Error"
         for (int i = 5; i < 50; i += 5)
          TheItems[i] = "Error: " + TheItems[i];
    
         this.DataContext = this;
       }
      }
    
      public class StringToForegroundConverter : IValueConverter
      {
       public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
       {
         if (value != null && value.ToString().StartsWith("Error"))
          return "Red";
         else
          return "DarkGray";
       }
    
       public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
       {
         throw new NotImplementedException();
       }
      }
    }
    


    Cheers,
    Olaf
    http://blogs.intuidev.com
    Saturday, May 1, 2010 8:20 AM
  • Hi NR,

    the sample I provided doesn't include any change-notification, it's just demonstrating the usage of a converter for your coloring. However, changing the List<string> to an ObservableCollection<string> will allow your ListBox to receive the notification that the ObservableCollection provides (INotifyCollectionChanged ).


    Cheers,
    Olaf
    http://blogs.intuidev.com
    • Marked as answer by Highlander4 Wednesday, May 19, 2010 2:53 AM
    Monday, May 17, 2010 6:31 AM

All replies

  • There are many fun ways to style WPF controls :) Here's a simple example for changing color of a listbox item based on a condition.

     

    XAML

      <ListBox x:Name="listBox" DisplayMemberPath="Name">
        <ListBox.ItemContainerStyle>
          <Style TargetType="ListBoxItem">
            <Style.Triggers>
              <DataTrigger Binding="{Binding IsHighlighted}" Value="True">
                <Setter Property="Foreground" Value="Red"></Setter>
              </DataTrigger>
            </Style.Triggers>
          </Style>
        </ListBox.ItemContainerStyle>
      </ListBox>

    CODE BEHIND

    public partial class Window1 : Window
    {
      public Window1()
      {
        InitializeComponent();
    
        listBox.ItemsSource = new List<DummyData>()
        {
          new DummyData() { IsHighlighted = true, Name = "Item 1"},
          new DummyData() { IsHighlighted = false, Name = "Item 2"},
          new DummyData() { IsHighlighted = true, Name = "Item 3"},
        };
      }
    }
    
    public class DummyData
    {
      public string Name { get; set; }
      public bool IsHighlighted { get; set; }
    }

    Warm regards,

    Matt

    Friday, April 30, 2010 2:47 AM
  • Hi,

    Just like Matt suggested, there are several ways to color a ListBox item at runtime. Which way to go depends on your scenario, can you explain the logic you want to implement?

    Thanks,
    Jie
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    If you have any feedback, please tell us.

    The All-In-One Code Framework Project
    My Blog (in Simplified Chinese)
    Friday, April 30, 2010 7:06 AM
  • I'm passing a string the list box.  If the string starts with "Error",  I want to list it in red.
    NR
    Saturday, May 1, 2010 12:24 AM
  • Hi NR,

    one of the classic scenarios for a simple converter. Here's a sample:

     

    <Window x:Class="WpfTests.ListBox_FieldValueToForegroundConverter"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTests"
        Title="ListBox_FieldValueToForegroundConverter" Height="300" Width="300">
      <ListBox Margin="5" ItemsSource="{Binding TheItems}" >
       <ListBox.Resources>
         <local:StringToForegroundConverter x:Key="ForegroundConverter"/>
       </ListBox.Resources>
       <ListBox.ItemTemplate>
         <DataTemplate>
          <TextBlock Text="{Binding}"
                Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
                Margin="2"/>
         </DataTemplate>
       </ListBox.ItemTemplate>
      </ListBox>
    </Window>
    

     

    Code-behind:

     

    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfTests
    {
      public partial class ListBox_FieldValueToForegroundConverter : Window
      {
       //The list the ListBox binds to
       public List<string> TheItems { get; set; }
    
       public ListBox_FieldValueToForegroundConverter()
       {
         InitializeComponent();
    
         //Build a list to bind to
         TheItems = new List<string>();
         for (int i = 1; i < 50; i++)
          TheItems.Add("Item #" + i.ToString());
    
         //Change a couple of items to start with "Error"
         for (int i = 5; i < 50; i += 5)
          TheItems[i] = "Error: " + TheItems[i];
    
         this.DataContext = this;
       }
      }
    
      public class StringToForegroundConverter : IValueConverter
      {
       public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
       {
         if (value != null && value.ToString().StartsWith("Error"))
          return "Red";
         else
          return "DarkGray";
       }
    
       public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
       {
         throw new NotImplementedException();
       }
      }
    }
    


    Cheers,
    Olaf
    http://blogs.intuidev.com
    Saturday, May 1, 2010 8:20 AM
  • Sorry, this doesn't seem work for me.  Nothing appears in my Listbox.  Using .net 4.   See the the code below:

    <Window x:Class="WpfApplication1.MainWindow"
    
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
    xmlns:local="clr-namespace:WpfApplication1"
    
    Title="MainWindow" Height="350" Width="525">
    
    <Grid>
    
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="52,74,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    
    <ListBox Height="100" HorizontalAlignment="Left" Name="listBox2" VerticalAlignment="Top" Width="214" ItemsSource="{Binding myItems}" Margin="169,55,0,0">
    
    
    <ListBox.Resources>
    
    <local:StringToForegroundConverter x:Key="ForegroundConverter"/>
    
    </ListBox.Resources>
    
    <ListBox.ItemTemplate>
    
    <DataTemplate>
    
    <TextBlock Text="{Binding}"
    
    Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
    
    Margin="2"/>
    
    </DataTemplate>
    
    </ListBox.ItemTemplate>
    
    </ListBox>
    
    </Grid>
    
    </Window>
    
    namespace WpfApplication1
    
    {
    
    /// <summary>
    
    /// Interaction logic for MainWindow.xaml
    
    /// </summary>
    
    public partial class MainWindow : Window
    
    {
    
    List<string> myItems = new List<string>();
    
    public MainWindow()
    
    { InitializeComponent(); }
    
    private void button1_Click(object sender, RoutedEventArgs e)
    
    {
    
    for (int i = 1; i < 20; i++)
    
    myItems.Add("Error_this item failed");
    
    for (int i = 1; i < 20; i++)
    
    myItems.Add("this item passed");
    
    this.DataContext = this;
    
    }
    
    }
    
    public class StringToForegroundConverter : IValueConverter
    
    {
    
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
    {
    
    if (value != null && value.ToString().StartsWith("Error"))
    
    return "Red";
    
    else
    
    return "DarkGray";
    
    }
    
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
    { throw new NotImplementedException(); } 
    
    }
    
    }
    

    NR
    Saturday, May 1, 2010 8:04 PM
  • Hi NR,

    you are missing the myItems property that the ListBox binds to - you only declared the member. Replace the line List<string> myItems = new List<string>(); with public List<string> MyItems { get; set; } and add the line MyItems = new List<string>(); to your button's click-handler.


    Cheers,
    Olaf
    http://blogs.intuidev.com
    • Marked as answer by Highlander4 Sunday, May 16, 2010 8:42 PM
    • Unmarked as answer by Highlander4 Sunday, May 16, 2010 9:05 PM
    Sunday, May 2, 2010 8:17 AM
  • Thanks Olaf.   It took me a while to get back to this. 

    It works as you said, however, if I click the button a second time, nothing happens.  It seems to work the first time only


    NR

    Sunday, May 16, 2010 8:42 PM
  • Hi NR,

    the sample I provided doesn't include any change-notification, it's just demonstrating the usage of a converter for your coloring. However, changing the List<string> to an ObservableCollection<string> will allow your ListBox to receive the notification that the ObservableCollection provides (INotifyCollectionChanged ).


    Cheers,
    Olaf
    http://blogs.intuidev.com
    • Marked as answer by Highlander4 Wednesday, May 19, 2010 2:53 AM
    Monday, May 17, 2010 6:31 AM
  • Thanks Olaf.   I changed the section below to my code as you suggested and it works fine now.  I can now modify it to make it applicable to other scenarios.

     

    public partial class MainWindow : Window

    {

     

     

    public System.Collections.ObjectModel.ObservableCollection<string> MyItems { get; set; }

     

     

    public MainWindow()

    {

    MyItems =

     

    new System.Collections.ObjectModel.ObservableCollection<string>();

    InitializeComponent();

     

     

    }

     

     

    private void button1_Click(object sender, RoutedEventArgs e)

    {

     

    MyItems.Add(textBox1.Text);

     

     

     

    this.DataContext = this;

     

    }

    }

     


    NR
    Wednesday, May 19, 2010 2:52 AM
  • Hey Matt,

    This helped me out.  Cut, Paste, Modify.....POW!

    Thanks man...

    Sunday, January 11, 2015 6:33 PM