如何在WPF ListView中根据Item类外条件显示Yes/No列值?
问题
我有一个简单的模型类:
public class Car { public string Make { get; init; } public string Model { get; init; } public string Year { get; init; } }
ViewModel里有两个列表:
public class ViewModel { public ObservableCollection<Car> Cars { get; } public List<Car> CanBeSold { get; } public ViewModel() { Car car1 = new() { Make = "Toyota", Model = "Corolla", Year = "2020" }; Car car2 = new() { Make = "Honda", Model = "Civic", Year = "2021" }; Car car3 = new() { Make = "Mitsubishi", Model = "Lancer", Year = "2017" }; Cars = new(); CanBeSold = new(); Cars.Add(car1); Cars.Add(car2); Cars.Add(car3); CanBeSold.Add(car2); } }
视图中把ListView绑定到Cars集合:
<ListView ItemsSource="{Binding Cars}"> <ListView.View> <GridView> <GridViewColumn Header="Make" DisplayMemberBinding="{Binding Path=Make}"/> <GridViewColumn Header="Model" DisplayMemberBinding="{Binding Path=Model}"/> <GridViewColumn Header="Year" DisplayMemberBinding="{Binding Path=Year}"/> <GridViewColumn Header="Can Be Sold"/> </GridView> </ListView.View> </ListView>
怎么实现根据Car是否在CanBeSold列表中,在“Can Be Sold”列显示“Yes/No”?
实现方案
方案一:用多值转换器(符合MVVM,推荐)
这是最规范的做法,不会破坏模型和ViewModel的职责分离:
- 先写一个多值转换器类,用来判断当前Car是否在CanBeSold集合里:
using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; public class CarCanBeSoldConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values[0] is Car car && values[1] is List<Car> canBeSoldList) { return canBeSoldList.Contains(car) ? "Yes" : "No"; } return "No"; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
- 在XAML的资源里声明这个转换器(记得替换
YourProjectNamespace为你实际的项目命名空间):
<Window.Resources> <xmlns:local="clr-namespace:YourProjectNamespace"/> <local:CarCanBeSoldConverter x:Key="CarCanBeSoldConverter"/> </Window.Resources>
- 修改ListView的“Can Be Sold”列,用MultiBinding把当前Car和ViewModel的CanBeSold集合传给转换器:
<GridViewColumn Header="Can Be Sold"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock> <TextBlock.Text> <MultiBinding Converter="{StaticResource CarCanBeSoldConverter}"> <Binding/> <!-- 绑定当前行的Car对象 --> <Binding Path="DataContext.CanBeSold" RelativeSource="{RelativeSource AncestorType=ListView}"/> <!-- 绑定ViewModel里的CanBeSold列表 --> </MultiBinding> </TextBlock.Text> </TextBlock> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn>
方案二:在ViewModel里加判断方法(简单直接)
如果不想写转换器,也可以在ViewModel里加个判断方法,再配合布尔转文本的小转换器:
- 在ViewModel里添加判断方法:
public bool IsCarCanBeSold(Car car) { return CanBeSold.Contains(car); }
- 写一个布尔转Yes/No的转换器:
using System; using System.Globalization; using System.Windows.Data; public class BoolToYesNoConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is bool b && b ? "Yes" : "No"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
- 在XAML资源里声明这个转换器,然后修改列的绑定:
<Window.Resources> <xmlns:local="clr-namespace:YourProjectNamespace"/> <local:BoolToYesNoConverter x:Key="BoolToYesNoConverter"/> </Window.Resources> <!-- 修改后的Can Be Sold列 --> <GridViewColumn Header="Can Be Sold"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=DataContext.IsCarCanBeSold(.), RelativeSource={RelativeSource AncestorType=ListView}, Converter={StaticResource BoolToYesNoConverter}}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn>
方案三:给Car模型加属性(不推荐,耦合性高)
如果项目很小,不在意耦合,可以直接给Car加个IsCanBeSold属性,在ViewModel里赋值:
- 修改Car模型:
public class Car { public string Make { get; init; } public string Model { get; init; } public string Year { get; init; } public bool IsCanBeSold { get; set; } }
- 在ViewModel构造函数里设置属性:
public ViewModel() { Car car1 = new() { Make = "Toyota", Model = "Corolla", Year = "2020" }; Car car2 = new() { Make = "Honda", Model = "Civic", Year = "2021", IsCanBeSold = true }; Car car3 = new() { Make = "Mitsubishi", Model = "Lancer", Year = "2017" }; // ... 原有添加集合的代码 }
- 直接绑定属性加转换器:
<GridViewColumn Header="Can Be Sold" DisplayMemberBinding="{Binding IsCanBeSold, Converter={StaticResource BoolToYesNoConverter}}"/>
(同样需要声明BoolToYesNoConverter)
内容的提问来源于stack exchange,提问作者AntikM
相关产品推荐
相关产品推荐

