相关文章推荐
深情的路灯  ·  illeegal memory ...·  2 月前    · 
活泼的饼干  ·  Android ...·  1 年前    · 
挂过科的海龟  ·  HttpResponse.BinaryWri ...·  1 年前    · 

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

Demo下载:

让我们尝试以最简单的形式创建一个 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>