Silverlight入门:第四部分 - 数据绑定
在之前的第三部分中,我们做了很多工作来获取公共Web服务返回的数据并让 其显示在控件中。我们已经用过了DataGrid控件,但它并不是我们真正想要的用 户界面,所以让我们自己来定义一个。为此,我们需要一个ItemsControl和一个 DataTemplate。这将让我们学习到XAML的绑定语法,以及如何利用更强大的数据 绑定信息。
在开始之前——先删除DataGrid
在开始之 前,让我们先删除并且只删除DataGrid,我们也不再需要它的程序集引用以及 xmlns,所以也可以大胆删除它们。
把DataGrid替换成ItemsControl,像 是这样:
1 <ItemsControl x:Name="SearchResults" Margin="0,8,0,0" Grid.Row="1" />
这里我们又要用到 Blend了,我们准备在Blend中为ItemControl修改ItemTemplate。ItemControl本 质上只是一个按照我们要求工作的解析控件。如果我们仅仅只是把DataGrid替换 成ItemControl,那么我们将得到:
ItemControl不知道我们想如何显示数据,所以我们要在模板中告诉它 ……让我们回到Blend。通常我们都在这里编辑(前面说到过)。
在框中显示发布消息的用户的头像。使用我们之前学到的布局知识可 以很容易地创建模板。我们在Blend中放置一个ResultObjects并右击选择编辑 ItemTemplate(在已生成项目菜单下)。
现在我们已经获得了一个可以填充内容的空模板。在随后的对话框中,我把 它命名为SearchResultsTemplate。现在我们处于布局编辑模式,可以在其中拖 拉或移动内容。我创建了一个基于表格的布局,这是我的模板的XAML:
1 <DataTemplate x:Key="SearchResultsTemplate">
2 <Grid Margin="4,0,4,8" d:DesignWidth="446" d:DesignHeight="68">
3 <Grid.ColumnDefinitions>
4 <ColumnDefinition Width="Auto" />
5 <ColumnDefinition Width="*" />
6 </Grid.ColumnDefinitions>
7 <Border VerticalAlignment="Top" Margin="8" Padding="2" Background="White">
8 <Image Width="40" Height="40" />
9 </Border>
10
11 <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="0,4,0,0">
12 <TextBlock x:Name="AuthorName" FontWeight="Bold" />
13 <Grid Margin="0,6,0,0">
14 <Grid.RowDefinitions>
15 <RowDefinition Height="Auto" />
16 <RowDefinition Height="2" />
17 <RowDefinition Height="Auto" />
18 </Grid.RowDefinitions>
19 <TextBlock x:Name="TweetMessage" TextWrapping="Wrap" />
20 <TextBlock x:Name="PublishDateLabel" Grid.Row="2" />
21 </Grid>
22 </StackPanel>
23 </Grid>
24 </DataTemplate>
我们还把ItemControl放入了ScrollViewer中,因为它本身没有提供滚动条:
1 <ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" BorderThickness="1">
2 <ItemsControl x:Name="SearchResults" Margin="0,8,0,0" Grid.Row="1" ItemTemplate="{StaticResource SearchResultsTemplate}" />
3 </ScrollViewer>
现在我们已经设置完控件了,但是我们还没有告诉它如何处理接收到的数据 。
XAML绑定语法
这里是我们写绑定语法的地方。你看,ItemsControl正在获取数据(记住, 我们没有改变代码,所以 SearchResults.ItemsSource仍然被设置为我们的 PagedCollectionView)。我们需要使用绑定来将实体元素映射到模板。基本的 XAML绑定语法是:
{Binding Path=<some-data-path>, Mode=<binding mode>}
你还能得到更多高级的功能,但我们将从简单的开始。比如说,将模板中的 图像元素绑定到TwitterSearchResult模型的头像,看起来像这样:
1 <Image Width="40" Height="40" Source="{Binding Path=Avatar, Mode=OneWay}" />
同时绑定作者到作者名称元素,像这样:
1 <TextBlock x:Name="AuthorName" FontWeight="Bold" Text="{Binding Path=Author, Mode=OneWay}" />
我们将它们的模式设置成OneWay,因为在不需要改变数据的情况下不需要使 用TwoWay。在发布日期的处理上,我们需要提供一些明确的数据格式,这可以通 过值转换器做到。
绑定一个值转换器
值转换器是实现IValueConverter接口的一些类,它们提供了正向和反向的转 换方法。我们打算在发布日期上采用明确的日期对象格式,所以我们将在项目中 一个被叫做转换器的文件夹中创建一个名为DateTimeConverter.cs的类。这个类 看起来像这样:
1 using System;
2 using System.Threading;
3 using System.Windows.Data;
4
5 namespace TwitterSearchMonitor.Converters
6 {
7 /*
8 * Use this converter for formatting dates in XAML databinding
9 * Example:
10 * Text="{Binding Path=PublishDate, Converter= {StaticResource DateTimeFormatter}, ConverterParameter=MMM yy}" />
11 *
12 * */
13 public class DateTimeConverter : IValueConverter
14 {
15 #region IValueConverter Members
16
17 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
18 {
19 DateTime? bindingDate = value as DateTime?;
20
21 if (culture == null)
22 {
23 culture = Thread.CurrentThread.CurrentUICulture;
24 }
25
26 if (bindingDate != null)
27 {
28 string dateTimeFormat = parameter as string;
29 return bindingDate.Value.ToString(dateTimeFormat, culture);
30 }
31
32 return string.Empty;
33 }
34
35 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
36 {
37 throw new NotImplementedException();
38 }
39
40 #endregion
41 }
42 }
我们要回到XAML页面来使用它(Search.xaml),还要为此添加xmlns声明和 资源。我们要使用的xmlns看起来像这样:
1 xmlns:converters="clr- namespace:TwitterSearchMonitor.Converters"
之后在XAML中的资源节中(其它模板被定义的地方),我们将为转换器添加 一个节点:
1 <navigation:Page.Resources>
2 <converters:DateTimeConverter x:Key="DateTimeFormatter" />
3 ...
之后我们就能在PublishDateLabel元素上使用我们的转换器了,像这样:
1 <TextBlock x:Name="PublishDateLabel" Text="{Binding Path=PublishDate,
2 Converter={StaticResource DateTimeFormatter},
3 ConverterParameter=dd-MMM-yyyy hh:mm tt}" Grid.Row="2" />
这将告诉XAML应该运行IValueConverter来得到输出。我们已经得到了想要的 精确的数据格式。所有这些用于绑定的额外语法,使我们得到了期望的解析结果 :
没错,我知道用twitpic作为搜索关键字获得了一些有趣的结果,但那是因为 用它作为搜索条件获得的数据刷新速度比较快!
很好,不是很难,不是吗?绑定语法对建设你的应用程序来说是至关重要的 。
存储一些设置和配置数据
存储最后一次登陆的TwitterID对我们的应用程序来说是很有用的功能,这样 当程序下一次启动的时候,就能从上次离开的地方继续。 此外,它还能保存 搜索条件历史,使我们可以在历史导航中查看。
为此,我们将使用Silverlight中的独立存储。它可以为存储简单数据开启一 个低信用度的用户区域。这里有更多关于独立存储的内容:
# 使用Silverlight中的独立存储
# 改变和增加独立存储配额要做到这一点,我将在Model文件夹中添加一个Helper类。这个辅助类将协助 我们在独立存储区域保存和读取数据。独立存储的基础是在其中创建一个文件, 并在需要的时候读取或写入数据。在我们的应用中,我们将用独立存储来保存键 值对数据(搜索条件/TwitterID)。以下是Helper.cs类的内容:
1 using System.IO.IsolatedStorage;
2
3 namespace TwitterSearchMonitor.Model
4 {
5 public class Helper
6 {
7 internal static string GetLatestTweetId(string searchTerm)
8 {
9 if (IsolatedStorageSettings.ApplicationSettings.Contains(searchTerm))
10 {
11 return IsolatedStorageSettings.ApplicationSettings [searchTerm].ToString();
12 }
13 else
14 {
15 return "0";
16 }
17 }
18
19 internal static void SaveLatestTweetId(string searchTerm, string latestId)
20 {
21 if (IsolatedStorageSettings.ApplicationSettings.Contains(searchTerm))
22 {
23 IsolatedStorageSettings.ApplicationSettings[searchTerm] = latestId;
24 }
25 else
26 {
27 IsolatedStorageSettings.ApplicationSettings.Add (searchTerm, latestId);
28 }
29 }
30 }
31 }
现在在Search.xaml.cs中,我们将在活动指针被设置后在SearchForTweetsEx 中添加如下内容:
1 _lastId = Helper.GetLatestTweetId(SearchTerm.Text); // get the latest ID from settings
2
3 Helper.SaveLatestTweetId(SearchTerm.Text, _lastId); // saving for history even if a result isn't found
在OnReadCompleted中,当我们关闭XMLReader后,还要添加如下内容:
1 Helper.SaveLatestTweetId(SearchTerm.Text, _lastId); //saving last tweet id
如果查找到搜索结果,则将查询条件和TwitterID存入独立存储。
总结
在本章节我们为控件设置了模板,并使用XAML语法绑定了一些简单的数据, 还为格式化视图中的信息添加了一个值转换器,最后还用独立存储机制保存了设 置信息。
现在我们的程序已经可以正常工作了,接下来让我们为它锦上添花。