WPF, XAML: How to style a ListBoxItem using binding on property of ListBox ItemsSource object?

39,682

Solution 1

Use ItemContainerStyle:

<ListBox ItemsSource="{Binding LogMessages}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Background" Value="{Binding Severity, Converter={StaticResource YourBackgroundConverter}}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Solution 2

Like Bojan commented, it's the RelativeSource which shouldnt be there. Use {Binding Path=Severity, Converter={StaticResource BackgroundSeverityConverter}} when you're binding to your data object. RelativeSource.TemplatedParent is for binding to ListBoxItem.

Additionally, something of a pet peeve of mine, you could consider using triggers, for example:

<Style x:Key="BindingAlternation" TargetType="{x:Type ListBoxItem}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Severity}" Value="1">
            <Setter Property="Background" Value="Green"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Severity}" Value="2">
            <Setter Property="Background" Value="Yellow"/>
        </DataTrigger>
        <!-- etc.. -->
    </Style.Triggers>
<Style x:Key="BindingAlternation" TargetType="{x:Type ListBoxItem}">

But that's just a personal preference....what you have there should work fine if you fix the binding.

Share:
39,682
Sean Kelly
Author by

Sean Kelly

Updated on December 21, 2020

Comments

  • Sean Kelly
    Sean Kelly over 3 years

    I have a ListBox which is bound to ObservableCollection of LogMessages.

    public ObservableCollection<LogMessage> LogMessages { get; set; }
    public LogMessageData()
    {
        this.LogMessages = new ObservableCollection<LogMessage>();
    }
    

    Each Message has two parameters:

    public class LogMessage
    {
        public string Msg { get; set; }
        public int Severity { get; set; }
        //code cut...
    }
    

    ListBox is getting filled with those Items, and I need to color-code (change a background color of ListBoxItem) list depending on a Severity parameter of a LogMessage item.

    Here's what I have now in XAML of user control showing the log:

        <UserControl.Resources>
        <AlternationConverter x:Key="BackgroundSeverityConverter">
            <SolidColorBrush>Green</SolidColorBrush>
            <SolidColorBrush>Yellow</SolidColorBrush>
            <SolidColorBrush>Red</SolidColorBrush>
        </AlternationConverter>
        <Style x:Key="BindingAlternation" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" 
                    Value="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                    Path=Severity, 
                    Converter={StaticResource BackgroundSeverityConverter}}"/>
        </Style>
        <DataTemplate x:Key="LogDataTemplate">
            <TextBlock x:Name="logItemTextBlock" Width="Auto" Height="Auto" 
            Text="{Binding Msg}"/>
        </DataTemplate>
    </UserControl.Resources>
    

    and an actual ListBox:

    <ListBox IsSynchronizedWithCurrentItem="True" 
        ItemTemplate="{DynamicResource LogDataTemplate}" 
        ItemsSource="{Binding LogFacility.LogMessages}" 
        x:Name="logListBox" Grid.Row="1" 
        ItemContainerStyle="{StaticResource BindingAlternation}" />
    

    The AlternationConverter is used because the Severity parameter of message is of type Int (0..3), and we can easily switch between styles using that one.

    The concept is clear, but so far it does not work for me. The Background color of ListBoxItem did not change.