WPF 入门教程 ListView控件(一)
ListView 控件在 Windows 应用程序中非常常用,用于表示数据列表。一个很好的例子是 Windows 资源管理器中的文件列表,其中每个文件都可以按其名称显示,如果需要,还可以显示包含有关大小、上次修改日期等信息的列。
WPF 中的 ListView 与 WinForms
如果您以前使用过 WinForms,那么您对 ListView 的实用性有一个很好的了解,但您应该意识到 WPF 中的 ListView 不像 WinForms 版本那样使用。再一次的主要区别在于,虽然 WinForms ListView 只是调用 Windows API 函数来呈现常见的 Windows ListView 控件,但 WPF ListView 是一个独立的控件,不依赖于 Windows API。
WPF ListView 确实将 ListViewItem 类用于其最基本的项目,但如果将其与 WinForms 版本进行比较,您可能会开始寻找 ImageIndex、Group 和 SubItems 等属性,但它们并不存在。WPF ListView 以完全不同的方式处理项目图像、组及其子项目等内容。
WPF ListView 控件在其最简单的形式中非常简单。事实上,它看起来很像 WPF ListBox,直到您开始向它添加专门的视图。这并不奇怪,因为 ListView 直接从 ListBox 控件继承。因此,默认的 ListView 实际上只是一个 ListBox,具有不同的选择模式(稍后会详细介绍)。
推荐一款好用的WPF MVVM框架开源控件库《Newbeecoder.UI》,WPF技术交流群:517200188
https://www.zhihu.com/video/1479756997817602048Demo下载:
让我们尝试以最简单的形式创建一个 ListView:
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewBasicSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewBasicSample" Height="200" Width="200">
<ListView Margin="10">
<ListViewItem>A ListView</ListViewItem>
<ListViewItem IsSelected="True">with several</ListViewItem>
<ListViewItem>items</ListViewItem>
</ListView>
</Grid>
</Window>
这非常简单,使用手动指定的 ListViewItem 来填充列表,除了代表每个项目的文本标签之外什么都没有 - 一个最小的 WPF ListView 控件。
带有图像的 ListViewItem
由于 WPF 的外观特性,为 ListViewItem 指定图像不仅仅是为属性分配图像 ID 或键。相反,您可以完全控制它并指定在 ListViewItem 中呈现图像和文本所需的控件。下面是一个例子:
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewBasicSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewBasicSample" Height="200" Width="200">
<ListView Margin="10">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" Margin="0,0,5,0" />
<TextBlock>Green</TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" Margin="0,0,5,0" />
<TextBlock>Blue</TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem IsSelected="True">
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_red.png" Margin="0,0,5,0" />
<TextBlock>Red</TextBlock>
</StackPanel>
</ListViewItem>
</ListView>
</Grid>
</Window>
我们在这里做的很简单。因为 ListViewItem 派生自 ContentControl 类,所以我们可以指定一个 WPF 控件作为其内容。在这种情况下,我们使用 StackPanel,它有一个 Image 和一个 TextBlock 作为它的子控件。
我们通过 XAML 代码手动填充了一个 ListView 控件,但在 WPF 中,一切都与数据绑定有关。本教程的另一部分详细解释了数据绑定的概念,但一般来说,它是关于将数据与布局分离。因此,让我们尝试将一些数据绑定到 ListView:
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewDataBindingSample" Height="300" Width="300">
<ListView Margin="10" Name="lvDataBinding"></ListView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.ListView_control
public partial class ListViewDataBindingSample : Window
public ListViewDataBindingSample()
InitializeComponent();
List<User> items = new List<User>();
items.Add(new User() { Name = "John Doe", Age = 42 });
items.Add(new User() { Name = "Jane Doe", Age = 39 });
items.Add(new User() { Name = "Sammy Doe", Age = 13 });
lvDataBinding.ItemsSource = items;
public class User
public string Name { get; set; }
public int Age { get; set; }
我们填充我们自己的 User 对象的列表,每个用户都有一个名字和一个年龄。一旦我们将列表分配给 ListView 的 ItemsSource 属性,数据绑定过程就会自动发生,但结果有点令人沮丧:
每个用户在 ListView 中由他们的类型名称表示。这是意料之中的,因为 .NET 不知道您希望如何显示数据,所以它只是在每个对象上调用 ToString() 方法并使用它来表示项目。
我们可以利用它的优势并覆盖 ToString() 方法,以获得更有意义的输出。尝试用这个版本替换 User 类:
public class User
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
return this.Name + ", " + this.Age + " years old";
这是一个更加用户友好的显示并且在某些情况下会很好,但是依赖一个简单的字符串并不是那么灵活。也许您希望文本的一部分为粗体或其他颜色?也许你想要一个图像?幸运的是,WPF 使用模板使这一切变得非常简单。
带有 ItemTemplate 的 ListView
WPF 是关于模板的,因此为 ListView 指定数据模板非常容易。在此示例中,我们将在每个项目中进行大量自定义格式设置,只是为了向您展示这使 WPF ListView 变得多么灵活。
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewItemTemplateSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewItemTemplateSample" Height="150" Width="350">
<ListView Margin="10" Name="lvDataBinding">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBlock Text=", " />
<TextBlock Text="Age: " />
<TextBlock Text="{Binding Age}" FontWeight="Bold" />
<TextBlock Text=" (" />
<TextBlock Text="{Binding Mail}" TextDecorations="Underline" Foreground="Blue" Cursor="Hand" />
<TextBlock Text=")" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.ListView_control
public partial class ListViewItemTemplateSample : Window
public ListViewItemTemplateSample()
InitializeComponent();
List<User> items = new List<User>();
items.Add(new User() { Name = "John Doe", Age = 42, Mail = "john@doe-family.com" });
items.Add(new User() { Name = "Jane Doe", Age = 39, Mail = "jane@doe-family.com" });
items.Add(new User() { Name = "Sammy Doe", Age = 13, Mail = "sammy.doe@gmail.com" });
lvDataBinding.ItemsSource = items;
public class User
public string Name { get; set; }
public int Age { get; set; }
public string Mail { get; set; }
我们使用一堆 TextBlock 控件来构建每个项目,其中我们将部分文本以粗体显示。对于我们添加到这个例子中的电子邮件地址,我们给它加下划线,给它一个蓝色并改变鼠标光标,使其表现得像一个超链接。
带有 GridView 的 ListView
我们使用了 WPF ListView 的最基本版本,也就是没有指定自定义 View 的版本。这导致 ListView 的行为非常类似于 WPF ListBox,但有一些细微的差异。真正的力量在于视图,而 WPF 带有一个内置的专门视图:GridView。
通过使用 GridView,您可以在 ListView 中获取多列数据,就像您在 Windows 资源管理器中看到的一样。为了确保每个人都能将其形象化,我们将从一个基本示例开始:
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewGridViewSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewGridViewSample" Height="200" Width="400">
<ListView Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.ListView_control
public partial class ListViewGridViewSample : Window
public ListViewGridViewSample()
InitializeComponent();
List<User> items = new List<User>();
items.Add(new User() { Name = "John Doe", Age = 42, Mail = "john@doe-family.com" });
items.Add(new User() { Name = "Jane Doe", Age = 39, Mail = "jane@doe-family.com" });
items.Add(new User() { Name = "Sammy Doe", Age = 7, Mail = "sammy.doe@gmail.com" });
lvUsers.ItemsSource = items;
public class User
public string Name { get; set; }
public int Age { get; set; }
public string Mail { get; set; }
因此,我们对测试数据使用与之前相同的 User 类,然后将其绑定到 ListView。这与我们在前几章中看到的完全相同,但是正如您从屏幕截图中看到的,布局非常不同。这就是数据绑定的威力——相同的数据,但以完全不同的方式呈现,只需更改标记即可。
在标记 (XAML) 中,我们使用 ListView.View 属性为 ListView 定义一个视图。我们将其设置为 GridView,这是目前 WPF 中唯一包含的视图类型(不过您可以轻松创建自己的视图类型!)。GridView 为我们提供了您在屏幕截图中看到的基于列的视图。
在 GridView 内部,我们定义了三列,我们希望显示的每条数据都对应一列。该 标题 属性用于指定我们想显示的列,然后我们用文字 DisplayMemberBinding 属性的值绑定到从我们的用户类的属性。
模板化单元格内容
使用 DisplayMemberBinding 属性几乎仅限于输出简单的字符串,根本没有自定义格式,但 WPF ListView 比这更灵活。通过指定 CellTemplate ,我们可以完全控制内容在特定列单元格中的呈现方式。
GridViewColumn 将使用 DisplayMemberBinding 作为其第一优先级(如果存在)。第二个选择是 CellTemplate 属性,我们将在此示例中使用它:
<Window x:Class="WpfTutorialSamples.ListView_control.ListViewGridViewCellTemplateSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewGridViewCellTemplateSample" Height="200" Width="400">
<ListView Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Mail}" TextDecorations="Underline" Foreground="Blue" Cursor="Hand" />
</DataTemplate>
</GridViewColumn.CellTemplate>