【问题标题】:How to bind backgroundcolor of WPF listview items?如何绑定 WPF listview 项目的背景颜色?
【发布时间】:2018-05-28 16:29:22
【问题描述】:

我是 WPF 的新手,我在网上阅读了很多类似的问题,但我的 listview 仍然没有工作。我想根据属性(红色、黄色或绿色)更改列表视图元素的背景颜色

我的 ListView 的itemsSource 是这个类的可观察列表:

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;
                }
            }
        }
    }
}

我在 xaml 中定义了我的列表视图,如下所示:

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

绑定不起作用,我的所有列表视图元素都没有背景颜色。我不需要通过ListView.Resources 绑定完全相同的解决方案,但我也没有在其他方法中成功。

【问题讨论】:

  • 为什么不返回画笔对象并在没有触发器的情况下将颜色绑定到属性?

标签: c# wpf


【解决方案1】:

如果您将触发器Style 从ListView.Resources 移动到StackPanel.Resources(并将TargetType 更改为StackPanel),那么将使用这种方法显示背景颜色。

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

您还需要考虑在ConnectionItem 上实现INotifyPropertyChanged,以便在更改Status 时更新颜色。

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;
              }               
          }
      }
  }

请注意,Status 和 Color 现在同时具有 get 和 set 访问器,并且 Status 是设置Color 属性,而不是直接设置_color 字段。

  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;
          }
      }
  }

您甚至可以更进一步,从ConnectionItem 中完全删除Color 属性(以及在Status 中设置它的开关)并在Style 触发器中使用Status 值。

连接项

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

【讨论】:

  • 感谢您的详细解答。我已经看到了实现 INotifyPropertyChanged 的​​这种方法,但就我而言,对于这样一个小功能来说,代码太多了。我认为@mm8 的微小变化也适用于我的用例
  • 不客气。 INotifyPropertyChanged 虽然是 xaml 绑定的基础。如果您希望通过更改 ConnectionItem 将 ListViewItem 的颜色从其初始值更改为您将需要实现它。有更多可重用的实现方法,但我选择了最基本的方法。您甚至可以使用 PropertyChanged.Fody nuget 包,它几乎会自动为您完成。
  • 啊,你是对的。我希望值从它的初始值改变。所以我想我必须实现 INotifyPropertyChanged 接口
【解决方案2】:

将背景绑定到 Color 属性。

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

并将 Color 属性设置为画笔对象

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;
               }
           }
        }
    }
}

【讨论】:

  • 这个解决方案听起来很棒,因为一旦可以动态更改为任何颜色,而不仅仅是我的红色绿色黄色字符串值...但是如果我应用您的更改,项目仍然没有背景颜色.甚至不是初始颜色“Brushes.Red”
【解决方案3】:

您的ListViewItem 样式未应用,因为您已将ItemContainerStyle 属性设置为另一个Style。您应该将触发器移至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>

【讨论】:

  • 太棒了!到目前为止也适用于画笔类型而不是字符串值。如果我测试了一些价值转换,我会标记这个答案
  • @team17:你的意思是什么时候你测试过?要使“值切换”起作用,您需要实现 INotifyPropertyChanged 并在 ConnectionItem 类中引发 PropertyChanged 事件。
猜你喜欢
  • 1970-01-01
  • 2012-03-10
  • 2016-03-13
  • 2011-09-19
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多