WPF, XAML: How to style a ListBoxItem using bindin

2020-02-03 15:28发布

问题:

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.

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


回答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.