ListView 继承自简单的没有特色的ListBox。增加了对基于列显示的支持,并增加了快速切换视图或显示模式的能力,而不需要重新绑定数据以及重新构建列表。
ListView类是一个特殊的列表类,它是专门针对显示相同数据的不同视图而设计的。如果要构建显示每个数据项几部分信息的多列视图,ListView 控件特别有用。ListView类继承自ListBox类,并使用 View 属性进行扩展。
GridView
GridView类继承自ViewBase类,表示具有多列的列表视图。通过GridVeiw.Columns 集合添加GridViewColumn 对象可定义这些列。
单元格模板
可以视图单元格模板 CellTemplate 属性来重写列,它与DataTemplate很相似,但是只能应用于一列数据。单元格模板并不局限于只能使用TextBlock属性,也可以使用其他元素,比如使用 转化器帮助从文件系统加载相应的图像文件。
创建自定义视图
如果GridView视图不能满足需要,可以创建自己的视图以扩展ListView 控件的功能。不过,这并不容易实现。
视图通过重写两个受保护的属性进行工作:DefaultStyleKey 和 ItemContainerDefaultStyleKey。这两个属性都返回名为 ResourceKey 的特殊对象,该对象指向在XAML中定义的样式。DefaultStyleKey 将被用于配置整个ListView控件的样式,而ItemContainerDefaultStyleKey 则将被用于配置ListView控件中的每个ListViewItem元素的样式。尽管这些样式可修改任意属性,但它们通常通过替换用于ListView 控件的ControlTemplate 以及用于每个ListViewItem元素的DataTemplate 进行工作。
视图类
这里除了ViewBase 所需的DefaultStyleKey 与 ItemContainerDefaultStyleKey 外,还另外定义了三个属性:ItemTemplate、SelectedBackground、SelectedBorderBrush,其中ItemTemplate用于使用时提供正确的数据模板,SelectedBackground与SelectedBorderBrush用于为视图传递额外信息,在视图样式中可以绑定到这两个属性来使用。
public class TileView : ViewBase
{
private DataTemplate itemTemplate;
public DataTemplate ItemTemplate
{
get { return itemTemplate; }
set { itemTemplate = value; }
}
private Brush selectedBackground = Brushes.Transparent;
public Brush SelectedBackground
{
get { return selectedBackground; }
set { selectedBackground = value; }
}
private Brush selectedBorderBrush = Brushes.Black;
public Brush SelectedBorderBrush
{
get { return selectedBorderBrush; }
set { selectedBorderBrush = value; }
}
protected override object DefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "TileView"); }
}
protected override object ItemContainerDefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "TileViewItem"); }
}
}
视图样式
视图样式需要放到资源文件,为了自动检索到,我们这里将其命名为Generic.xaml 并放到Themes文件夹下。视图样式中主要为 ListView 的 ItemsPanel 属性应用了 WrapPanel,将View.ItemTemplate 绑定到ListViewItem的 ContentTemplate属性上,同时应用了再视图里面定义的 SelectedBackground与SelectedBorderBrush 这两个属性。
Themes/Generic.xaml
创建视图
我们在窗口资源里面来创建视图,主要需要为视图类提供数据模板,如果有需要的话,也可以为在视图类里面定义的SelectedBackground与SelectedBorderBrush 这两个属性提供数据。
使用视图
使用视图比较简单,视图已经在窗口资源里面定义了,只需要绑定到ListView的View属性上即可。因为这里创建了多个视图,我们可以根据用户选择来使用不同的视图。
Choose your view:
NormalGridView
ImageView
ImageDetailView
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem selectedItem = (ComboBoxItem)((ComboBox)sender).SelectedItem;
customListView.View = (ViewBase)this.FindResource(selectedItem.Content);
}
下面给出完整代码,Themes/Generic.xmal 在前面已经完整给出了,这里不再重复
MainWindow.xaml
Choose your view:
GridView
ImageView
ImageDetailView
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace TestListView;
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual bool SetProperty(ref T member, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer.Default.Equals(member, value))
{
return false;
}
member = value;
OnPropertyChanged(propertyName);
return true;
}
}
public class Order : ViewModelBase
{
public decimal price = 0;
public decimal Price { get => price; set => SetProperty(ref price, value); }
public int volume = 0;
public int Volume { get => volume; set => SetProperty(ref volume, value); }
public DateTime orderDate = DateTime.Now;
public DateTime OrderDate { get => orderDate; set => SetProperty(ref orderDate, value); }
public string image = string.Empty;
public string Image { get => image; set => SetProperty(ref image, value); }
}
public class ImagePathConverter : IValueConverter
{
private string imageDirectory = Directory.GetCurrentDirectory();
public string ImageDirectory
{
get { return imageDirectory; }
set { imageDirectory = value; }
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string imagePath = Path.Combine(ImageDirectory, (string)value);
return new BitmapImage(new Uri(imagePath));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
}
public class TileView : ViewBase
{
private DataTemplate itemTemplate;
public DataTemplate ItemTemplate
{
get { return itemTemplate; }
set { itemTemplate = value; }
}
private Brush selectedBackground = Brushes.Transparent;
public Brush SelectedBackground
{
get { return selectedBackground; }
set { selectedBackground = value; }
}
private Brush selectedBorderBrush = Brushes.Black;
public Brush SelectedBorderBrush
{
get { return selectedBorderBrush; }
set { selectedBorderBrush = value; }
}
protected override object DefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "TileView"); }
}
protected override object ItemContainerDefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "TileViewItem"); }
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
myGrid.DataContext = this;
InitOrder();
}
public ObservableCollection Orders { get; set; } = new();
public void InitOrder()
{
Order order1 = new Order();
Order order2 = new Order();
Order order3 = new Order();
Order order4 = new Order();
order1.Price = 100;
order1.Volume = 10;
order1.Image = "image1.gif";
order2.Price = 1000;
order2.Volume = 100;
order2.Image = "image2.gif";
order3.Price = 10000;
order3.Volume = 1000;
order3.Image = "image3.gif";
order4.Price = 100000;
order4.Volume = 10000;
order4.Image = "image4.gif";
Orders.Add(order1);
Orders.Add(order2);
Orders.Add(order3);
Orders.Add(order4);
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem selectedItem = (ComboBoxItem)((ComboBox)sender).SelectedItem;
customListView.View = (ViewBase)this.FindResource(selectedItem.Content);
}
}