以编程方式更改ListView行的背景颜色(wpf)

10
我有一个类,通过传递对象列表来填充ListView。该类使用反射查看每个对象的属性以生成ListView。如何更改ListView中一行的背景颜色。
这个页面正是我正在寻找的。唯一的问题是我的ListView绑定到对象列表。换句话说,ListView的每个项都是绑定的对象,而不是ListViewItem。我假设这就是为什么我无法将ListView中的某些项强制转换为ListViewItem的原因。例如,当我执行以下操作时:
ListViewItem someItem = (ListViewItem)listView1.Items[0];

我遇到了InvalidCastException异常,因为如果我像这样在ListView中物理添加对象:listview.items.add(someObject),那么这将起作用,但是因为我正在将列表绑定到ListView,所以该行不起作用。我认为这就是我无法进行转换的原因。我想要进行转换的原因是ListViewItem具有Background属性。
编辑
我可以在前12个对象中尝试以下操作:
for (int i = 0; i < listView1.Items.Count; i++)
{
    var lvitem = listView1.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
    lvitem.Foreground = Brushes.Green;                
}

我遇到了这个错误:

first try

我也尝试过这个:

foreach (Tiro t in listView1.Items)
{
    var lvitem = listView1.ItemContainerGenerator.ContainerFromItem(t) as ListViewItem;
    if (t.numero == 0 || t.numero == 37)
    {
        //lvitem.Background = Brushes.Green;
        lvitem.Foreground = Brushes.Green;
    }
    else if (t.numero % 2 == 0)
    {
        //lvitem.Background = Brushes.Red;
        lvitem.Foreground = Brushes.Red;
    }
    else
    {
        //lvitem.Background = Brushes.Gray;
        lvitem.Foreground = Brushes.Black;
    }

}

我得到了相同的错误:

enter image description here

我不明白为什么在第12次迭代后lvitem为空?
它只适用于正在显示的项目....
6个回答

10

您需要引入ViewModel,而不是削减WPF UI。例如,我可以按如下方式创建一个

public class ItemVM : INotifyPropertyChanged // if you want runtime changes to be reflected in the UI
{
  public string Text {... raise property change in setter }
  public Color BackgroundColor {... ditto... }
}

接下来在您的DataContext中创建一个这些对象的列表属性,以便您的ListView可以绑定到它。

// e.g. MainWindow
    public IEnumerable<ItemVM> Items { get; set; }

现在你需要做的就是将你的ListView绑定到这个集合,并正确地连接UI的DataContext。

       <ListView x:Name="MyListView" ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Text}">
                    <TextBlock.Background>
                        <SolidColorBrush Color="{Binding BackgroundColor}"/>
                    </TextBlock.Background>
                    </TextBlock>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Click="Button_Click" Content="Go PaleGreen"/>

现在更改背景颜色很容易。只需将相应的ItemVM对象的属性设置为所需的颜色即可。例如,要将所有项目设置为PaleGreen:

private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (var item in Items)
            item.BackgroundColor = Colors.PaleGreen;
    }

4
您可以使用ItemContainerGenerator,例如:
var lvitem = listView.ItemContainerGenerator.ContainerFromItem(item) as ListViewItem;
var lvitem = listView.ItemContainerGenerator.ContainerFromIndex(0) as ListViewItem;

默认情况下,ListView 是虚拟化的,这意味着 ListViewItems 会根据需要动态创建(仅在项目实际可见时),因此上述方法将不返回当前不可见的项目容器。

鉴于这种情况,通常最好通过在 ItemContainerStyle 中使用 Setter 定义 Background 属性绑定。


我现在能够做更多的事情了,谢谢。但是我无法改变颜色。我会继续尝试的。 - Tono Nam
lvitem.Background = Brushes.AliceBlue; 我需要使用Brushes而不是Colors。 - Tono Nam
嗯,那是有些常识。 - H.B.
为什么我无法将所有项目都转换?我只能转换前12个项目。 - Tono Nam
这是由于虚拟化的原因,只有在列表中可见时才会创建这些项目。 - H.B.

3

当使用ItemContainerGenerator时,请注意容器是异步生成的。生成器公开了一个状态改变事件,你可以监听它:

listView.ItemContainerGenerator.StatusChanged += new EventHandler(ContainerStatusChanged);     

private void ContainerStatusChanged(object sender, EventArgs e)  
{  
    if (listView.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)  
    {  
        foreach (Tiro t in listView1.Items)
        {
            ...
        }
    }  
}

不确定是否会产生任何奇怪的绘图效果(闪烁)。

另一个选项是使用数据模板而不是在代码中构建列表视图项。但您可能需要为显示目的向您的视图模型添加一些属性。


1
假设你的ListBox中的项是类型为Foo的,而在ListBox中,你将显示每个Foo项的Foo.ItemInfo,最后假设有一个名为Status的属性,它确定了你想要如何在ListBox中显示每个Foo.ItemInfo与背景、前景、字体样式和工具提示文本相关。根据这些要求,在你的XAML中添加以下内容:
<ListBox FontFamily="Courier New"
         HorizontalAlignment="Left"
      ...
      ...other ListBox attributes...
      ...
    <ListBox.Resources>
        <local:BGConverter x:Key="BackgroundConverter"/>
        <local:FGConverter x:Key="ForegroundConverter"/>
        <local:FSConverter x:Key="FontStyleConverter"/>
        <local:TTConverter x:Key="ToolTipConverter"/>
    </ListBox.Resources>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ItemInfo}"
                Background="{Binding Converter={StaticResource BackgroundConverter}}"
                FontStyle="{Binding Converter={StaticResource FontStyleConverter}}"
                Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
                ToolTip="{Binding Converter={StaticResource ToolTipConverter}}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

接下来,在你的MainWindow.xaml.cs中(或者你命名的XAML文件所对应的文件),添加以下内容,使用C#语言:

public class BGConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Foo foo = (Foo)value;
        string bgColor = "Gray";

        switch(foo.Status)
        {
            case 0: 
                bgColor = "White";
                break;

            case 1: 
                bgColor = "Cyan";
                break;

            case 2: 
                bgColor = "Yellow";
                break;
        }

        return bgColor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class FSConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Foo foo = (Foo)value;
        string fStyle = "Normal";

        switch(foo.Status)
        {
            case 0:
                fStyle = "Normal";
                break;

            case 1: 
                fStyle = "Oblique";
                break;

            case 2: 
                fStyle = "Italic";
                break;
        }

        return fStyle;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}


public class FGConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Foo foo = (Foo)value;
        string fgColor = "Black";

        switch(foo.Status)
        {
            case 0: 
                fgColor = "Blue";
                break;

            case 1: 
                fgColor = "Brown";
                break;

            case 2: 
                fgColor = "DarkBlue";
                break;
        }

        return fgColor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class TTipConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Foo foo = (Foo)value;
        string ttText = "No tool tips for this item.";

        switch(foo.Status)
        {
            case 0: 
                ttText = "The item has not been processed";
                break;

            case 1: 
                ttText = "The item has been processed but not saved";
                break;

            case 2: 
                ttText = "The item has been processed and saved";
                break;
        }

        return ttText ;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这是我发现有效的方法之一...毫无疑问还有许多其他方法,你的结果可能会有所不同...
无论如何,希望对你有帮助。

1

经过一些搜索,我找到了自己的解决方案。我使用Listview.ItemsSource,并将List用作源。然后我可以设置List中指定ListViewItem的背景,只需刷新listview即可。

XAML:

 <ListView x:Name="listView" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="IP"  DisplayMemberBinding="{Binding IP}" Width="Auto"/>
                        <GridViewColumn Header="PING" DisplayMemberBinding="{Binding Ping}" Width="Auto"/>
                        <GridViewColumn Header="Host Name" DisplayMemberBinding="{Binding DNS}" Width="Auto"/>
                        <GridViewColumn Header="Mac" DisplayMemberBinding="{Binding MAC}" Width="Auto"/>
                        <GridViewColumn Header="Výrobce" DisplayMemberBinding="{Binding Manufacturer}" Width="Auto"/>
                    </GridView>
                </ListView.View>
            </ListView>

使用灰色背景填充ListView项:
    List<ListViewItem> ITEMS = new List<ListViewItem>();
    private void button_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 1; i < 20; i++)
        {
            ListViewItem OneItem = new ListViewItem();
            OneItem.Background = Brushes.LightGray;
            OneItem.Content = new Device() { IP = "1.1.1.1", Ping = "30ms", DNS = "XYZ", MAC = "2F:3C:5F:41:F9", Manufacturer = "Intel" };
            ITEMS.Add(OneItem);
            listView.ItemsSource = ITEMS;
        }
        listView.Items.Refresh();
    }
    public class Device
    {
        public string IP { get; set; }
        public string Ping { get; set; }
        public string DNS { get; set; }
        public string MAC { get; set; }
        public string Manufacturer { get; set; }
    }

创建行变色的方法:
    private void ChangeRowColor(int RowIndex,SolidColorBrush NewBackground)
    {
        ITEMS[RowIndex].Background = NewBackground;
        listView.Items.Refresh();
    }

使用它:
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        ChangeRowColor(4, Brushes.Green);
    }

0
  List<ListViewItem> ITEMS = new List<ListViewItem>();
private void loadListView(ListView lv)
{
    int numberOfRows = 20;
    string[] student_number, first_name, last_name, middle_name, extension, course, year, section;
      //    ...... Assign values to the arrays above...
    for (int h = 0; h <= numberOfRows - 1; h++)
        {
            ListViewItem OneItem = new ListViewItem();
            OneItem.Background = course[h] == "Grade" ? Brushes.Red : Brushes.Transparent; //Decide the color of the Row
            OneItem.Content = new Student
            {
                Student_Number = student_number[h],
                Course = course[h],
                Section = section[h],
                Year = year[h],
                FullName = first_name[h] + " " + middle_name[h] + ". " + last_name[h] + " " + extension[h]
            };
            ITEMS.Add(OneItem);
            lv.ItemsSource = ITEMS;
        }
        lv.Items.Refresh();
}
public class Student
{
    public string Student_Number { get; set; }
    public string FullName { get; set; }
    public string Course { get; set; }
    public string Section { get; set; }
    public string Year { get; set; }
}

输出截图


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接