Mark Bonafe
Mark Bonafe

Reputation: 1493

WPF Color a ListBoxItem based on a property

I have looked at this answer, but it is not working for me for some reason. I am using an Observable Collection of LookupEntity objects:

public class LookupEntity
{
    public bool IsSelected { get; set; }
    public int Id { get; set; }
    public string Code { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public bool IsInactive { get; set; }
 }

What I need is for the background color of an inactive item (IsInactive=True) to be different than the other items. I have tried two approaches. The first is to use a DataTrigger and a Template. This should work, but it is not:

    <ListBox x:Name="RecordList"
    Grid.Row="2"
    MinWidth="200"
    ItemsSource="{Binding MaintenanceList, Mode=TwoWay}"
    HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
    VerticalAlignment="Stretch"
    BorderThickness="0"
    SelectedValue="{Binding SelectedItem, Mode=TwoWay}"                            
    IsEnabled="{Binding ContentVM.AddEnabled}"
    SelectionChanged="ListBox_SelectionChanged">
    <ListBox.Resources>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=IsInactive}" Value="True">
                    <Setter Property="Background" Value="PaleVioletRed"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate DataType="{x:Type utility:LookupEntity}">
            <TextBlock 
        Text="{Binding Title}"
        ToolTip="{Binding Description}"
        TextWrapping="NoWrap"
        HorizontalAlignment="Left"/>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>

The second approach works, but it depends on a Background Color property in the LookupEntity object. I don't like this approach because it gives display responsibility to an object that shouldn't have any knowledge of how it's displayed. Adding this property to the LookupEntity:

    public SolidColorBrush BackgroundColor
    {
        get { return IsInactive ? Brushes.PaleVioletRed : Brushes.Transparent; }
    }

And binding the Background property of the DataTemplate works, but it's not acceptable.

    <ListBox.Resources>
        <DataTemplate DataType="{x:Type utility:LookupEntity}">
            <TextBlock 
        Text="{Binding Title}"
        ToolTip="{Binding Description}"
        TextWrapping="NoWrap"
        HorizontalAlignment="Left"
        Background="{Binding BackgroundColor}"/>
        </DataTemplate>
    </ListBox.Resources>

I'd like to place the responsibility for the Background color in a skin / resource, but I can't with this setup. Is there something I've missed?

Upvotes: 0

Views: 825

Answers (1)

Bartosz W&#243;jtowicz
Bartosz W&#243;jtowicz

Reputation: 1401

Your LookupEntity class should implement INotifyPropertyChanged interface. And you should raise the PropertyChanged event when IsInactive changes.

public class LookupEntity : INotifyPropertyChanged
{
    private bool _isInactive;

    public bool IsSelected { get; set; }
    public int Id { get; set; }
    public string Code { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }

    public bool IsInactive
    {
        get { return _isInactive; }
        set
        {
            _isInactive = value;
            OnPropertyChanged("IsInactive");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

EDIT: You can try binding the property directly instead of using a trigger. However, you need to use a value converter, which you have to implement.

<Style TargetType="ListBoxItem" Background="{Binding IsInactive, Converter={StaticResource boolToColorConverter}}">
</Style>

Upvotes: 3

Related Questions