简体   繁体   中英

How to bind backgroundcolor of WPF listview items?

I am new to WPF and I have read a lot of similar questions on the web, but I still do not get my listview work. I want to change the background color of a list view element depending of a property (red, yellow or green)

The itemsSource of my ListView is an observable list of this class:

public class ConnectionItem 
{
    public ConnectionItem(string name)
    {
        Name = name;
    }

    public string Name { get; }
    private string _color = "Red";
    public string Color { get => _color; }
    private ConnectionStatus _status;
    public ConnectionStatus Status
    {
        set
        {
            if (value == _status)
            {
                return;
            }
            else
            {
                switch (value)
                {
                    case ConnectionStatus.Connected:
                        _color = "Yellow";
                        break;
                    case ConnectionStatus.Ready:
                        _color = "Green";
                        break;
                    default:
                        _color = "Red";
                        break;
                }
            }
        }
    }
}

And I have defined my listview in xaml as follows:

<ListView x:Name="lvConnections">
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.Resources>
                <Style TargetType="ListViewItem">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Color}" Value="Green">
                            <Setter Property="Background" Value="Green"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Color}" Value="Red">
                            <Setter Property="Background" Value="Red"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Color}" Value="Yellow">
                            <Setter Property="Background" Value="Yellow"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ListView.Resources>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <StackPanel  Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
                            <TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
                        </StackPanel>
                    </Grid>

                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

The binding does not work and all my listview element have no background color. I do not need exactly the same solution via ListView.Resources binding, but I also have did not succed in other approaches.

bind the background to the Color property.

<ListView x:Name="lvConnections">
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListViewItem}">
                <EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.Resources>
            <Style TargetType="ListViewItem">
               <Setter Property="Background" Value="{Binding Color}"/>
            </Style>
        </ListView.Resources>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <StackPanel  Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
                        <TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
                    </StackPanel>
                </Grid>

            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

and set the Color property to a brush object

public class ConnectionItem 
{
    public ConnectionItem(string name)
    {
        Name = name;
    }

    public string Name { get; }
    private Brush _color = Brushes.Red;
    public Brush Color { get => _color; }
    private ConnectionStatus _status;
    public ConnectionStatus Status
    {
        set
        {
            if (value == _status)
            {
                return;
            }
            else
            {
                switch (value)
                {
                    case ConnectionStatus.Connected:
                        _color = Brushes.Yellow;
                        break;
                    case ConnectionStatus.Ready:
                        _color = Brushes.Green;
                        break;
                    default:
                        _color = Brushes.Red;
                        break;
               }
           }
        }
    }
}

If you move the trigger Style from ListView.Resources to StackPanel.Resources (and change the TargetType to StackPanel ) then the background colors will display using this approach.

<StackPanel  Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal">
    <StackPanel.Resources>
        <Style TargetType="StackPanel">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Color}" Value="Green">
                    <Setter Property="Background" Value="Green"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Color}" Value="Red">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Color}" Value="Yellow">
                    <Setter Property="Background" Value="Yellow"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </StackPanel.Resources>
    <TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
</StackPanel>

You will also need to look at implementing INotifyPropertyChanged on ConnectionItem for the colors to update when Status is changed.

public class ConnectionItem : INotifyPropertyChanged
  {
      public event PropertyChangedEventHandler PropertyChanged;

      public ConnectionItem(string name)
      {
          Name = name;
      }

      public string Name { get; }

      private string _color = "Red";
      public string Color
      {
          get => _color;
          set
          {
              if (value == _color) return;
              _color = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
          }
      }

      private ConnectionStatus _status;
      public ConnectionStatus Status
      {
          get => _status;
          set
          {
              if (value == _status) return;
              _status = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Status"));
              switch (value)
              {
                  case ConnectionStatus.Connected:
                      Color = "Yellow";
                      break;
                  case ConnectionStatus.Ready:
                      Color = "Green";
                      break;
                  default:
                      Color = "Red";
                      break;
              }               
          }
      }
  }

Note that Status and Color now have both get and set accessors and that that Status is setting the Color property rather than directly setting the _color field.

  public partial class MainWindow : Window
  {
      public MainWindow()
      {
          InitializeComponent();

          lvConnections.ItemsSource = new ObservableCollection<ConnectionItem>()
          {
              new ConnectionItem("Starts Connected") { Status = ConnectionStatus.Connected, },
              new ConnectionItem("Starts Ready") { Status = ConnectionStatus.Ready, },
              new ConnectionItem("Starts Default"),
          };
      }

      private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
      {
          var item = (sender as ListViewItem)?.DataContext as ConnectionItem;
          switch (item.Status)
          {
              case ConnectionStatus.Connected:
                  item.Status = ConnectionStatus.Ready;
                  break;
              case ConnectionStatus.Ready:
                  item.Status = ConnectionStatus.Disconnected;
                  break;
              default:
                  item.Status = ConnectionStatus.Connected;
                  break;
          }
      }
  }

You can even go one step further, remove the Color property from ConnectionItem altogether (and the switch setting it in Status ) and use Status values in the Style triggers.

ConnectionItem

public class ConnectionItem : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ConnectionItem(string name)
    {
        Name = name;
    }

    public string Name { get; }

    private ConnectionStatus _status;
    public ConnectionStatus Status
    {
        get => _status;
        set
        {
            if (value == _status) return;
            _status = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Status"));
        }
    }
}

Style

  <Style TargetType="StackPanel">
      <Style.Triggers>
          <DataTrigger Binding="{Binding Status}" Value="Ready">
              <Setter Property="Background" Value="Green"/>
          </DataTrigger>
          <DataTrigger Binding="{Binding Status}" Value="Disconnected">
              <Setter Property="Background" Value="Red"/>
          </DataTrigger>
          <DataTrigger Binding="{Binding Status}" Value="Connected">
              <Setter Property="Background" Value="Yellow"/>
          </DataTrigger>
      </Style.Triggers>
  </Style>

Your ListViewItem style doesn't get applied because your have set the ItemContainerStyle property to another Style . You should move your triggers to the ItemContainerStyle :

<ListView x:Name="lvConnections">
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Color}" Value="Green">
                    <Setter Property="Background" Value="Green"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Color}" Value="Red">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Color}" Value="Yellow">
                    <Setter Property="Background" Value="Yellow"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <StackPanel  Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
                    <TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM