空洞的理论让人心烦。所以我打算从一个实例开始学习WPF。这个例子用来产生一个交替显示背景色的GridView。我看在网上有很多人都在问这样的问题,也有很多热心朋友的答复。但是所有这些答复都是基于MSDN网站上的描述。这是MSDN上的说明:http://msdn.microsoft.com/zh-cn/library/ms750769.aspx。
我仍然使用这里例子作为对WPF的入门。当然了,我的重点不在如何实现交替显示背景色的GridView,而是以此入手,挖掘更多的WPF的知识。希望大家给出意见和建议,一起进步。
MSDN中有3种方法来实现了这一效果。这是其中的一个:派生一个新的ListView来实现交替产生背景色的效果。
这是定义的新的派生类源代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Windows.Controls;
6 using System.Windows.Media;
7
8 namespace WPFGridColor
9 {
10 class SubListView:ListView
11 {
12 protected override void PrepareContainerForItemOverride(System.Windows.DependencyObject element, object item)
13 {
14 //Comment:
15 // This method is called when the ListViewItem is preparing to display.
16 // It means that the method is based on the ListViewItem.
17 base.PrepareContainerForItemOverride(element, item);
18
19 if (View is GridView)
20 {
21 //Trying to get the index.
22 //element represents the ListViewItem object,
23 //and we could get the current item's index by this method.
24 int index = ItemContainerGenerator.IndexFromContainer(element);
25
26 ListViewItem lvi = element as ListViewItem;
27 if (index % 2 == 0)
28 {
29 lvi.Background = Brushes.LightBlue;
30 }
31 else
32 {
33 lvi.Background = Brushes.Beige;
34 }
35 }
36 }
37 }
38 }
39
可以看见,这里首先定义了一个派生自ListView的新类,在新类中重写了PrepareContainerForItemOverride方法。先看看PrepareContainerForItemOverride方法。在MSDN中的解释是:为ListViewItem设置样式、模板和绑定。在这里,应该注意两点:
- 它的作用对象是ListViewItem。即仅对其中的一个项起作用。在这里例子里面,可以理解为当要表示某一行时可以为这一行指定样式、模板和绑定。因此,它的参数中应该包含对这个ListViewItem的引用。
- 从名字上来说,方法的目的是Prepare Container for Item。 因此,这里是通过重载来设定ListVirewItem的样式、模板和绑定,进而最终影响Container的表示方式。
再进一步可以看见一个ItemContainerGenerator.IndexFromContainer。IndexFromContainer可以知道这是用来取得该ListViewItem在整个Container中的索引。但是ItemContainerGenerator是什么东西呢?MSDN的解释很难理解。这是我的看法:
- ItemContainerGenerator是ListView的一个属性。它的作用在于“负责为其宿主(如 ItemsControl)生成 用户界面 (UI)。它维护控件数据视图中的项与对应的 对象之间的关联。”。在这里我的理解是它可以定义ListView(准确的说应该是ItemsControl)与其中的ListViewItem的关系。
- ItemContainerGenerator作为一个维护ItemsControl与用户界面关系的桥梁,主要提供了以下方法:
ContainerFromIndex 根据索引返回对应于ItemCollection中指定索引项的元素(DependencyObject)。
ContainerFromItem 返回对应于指定项的UIElement。
IndexFromContainer 返回对应于指定生成的 的项的索引。
ItemFromContainer 返回对应于指定生成的UIElement 的项。 - 可以看出这里有两个非常重要的实体关系:ListView的UI对象集合ItemsControl和值的集合ItemCollection。ItemContainerGenerator处理的就是这两者之间的关系。
- ItemsControl是所有集合控件的主要成员。它需要一个容器类型作为宿主。如:ListView和ComboBox。
- 这里的Container其实就是UIElement。也就是在画面上看见的一行。
到这里,再理解整个SubListView就很容易了。现在再来看我们在xaml中的实现
1 <Window x:Class="WPFGridColor.MainWnd"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:appnmspc="clr-namespace:WPFGridColor"
5 Title="WPF Grid Back Color Investigation" Height="300" Width="500">
6 <Window.Resources>
7 <XmlDataProvider x:Key="CustomersDS" Source="C:\data.xml" />
8 </Window.Resources>
9 <Grid>
10 <appnmspc:SubListView ItemsSource="{Binding Source={StaticResource CustomersDS}, XPath=/Customers/Customer}">
11 <appnmspc:SubListView.View>
12 <GridView>
13 <GridViewColumn DisplayMemberBinding="{Binding XPath=Code}"
14 Header="Code" Width="120"/>
15 <GridViewColumn DisplayMemberBinding="{Binding XPath=Name}"
16 Header="Name" Width="120"/>
17 <GridViewColumn DisplayMemberBinding="{Binding XPath=Country}"
18 Header="Country" Width="120"/>
19 </GridView>
20 </appnmspc:SubListView.View>
21 </appnmspc:SubListView>
22 </Grid>
23 </Window>
24
这里需要注意几点:
- 第四行,这是在引用自己定义的程序集。需要注意xaml的名称空间和程序集的名称空间的区别,以及如何在xaml中引用程序集的名称空间。
- 第六行,定义了一个该Window的资源。
- 第十行,使用数据源绑定。关于资源和数据源绑定,以后将会做进一步的研究。