原文地址:
源代码: http://aka.ms/absbeginnerdevwp8
PDF版本: http://aka.ms/absbeginnerdevwp8pdf
我们花了9节课来学习Windows Phone的基础知识,并且已经创建了一个简单的应用程序。PetSounds应用程序是一个好的开始,但是它存在一些限制。当前只有一类声音,即动物的声音,我们有两个按钮,因此可以有两类声音。
我们可以把它转变成一个更全面的具备不同类别声音的声音面板应用程序,甚至是我们可以录制自定义声音。我们需要一个好的方式来表示应用程序中的声音类别,在Visual Studio中至少有一个可用的模板,它将提供一个很好的起点以帮助我们非常接近我们的想法。
所以在本节课我将学习两个项目模板以更多了解它们能做什么,并确定它们的内置功能和新的SoundBoard应用程序需求之间的契合点。
这里是本课的计划:
- 创建一个Windows Phone数据绑定应用程序(Databound App)项目模板示例以发现它的内置功能并查看其中的代码以理解实现这些功能方法。
- 对Windows Phone透视应用程序(Pivot App)项目模板重复该过程。
1. 理解Windows Phone数据绑定应用程序项目模板的功能
在Visual Studio中,选择文件菜单中的新建|项目以打开新建项目对话框:
- 确认您位于已安装 | 模板 | Visual C# | Windows Phone
- 选择Windows Phone数据绑定应用程序项目模板。
- 您不需要修改名称,我们将在以后删除这个项目。
- 单击确定。
一旦项目被创建,在进行任何其他操作之前,按F5启动调试。这使我们能够观察“开箱即用”的功能。
当应用程序运行时,您将看到主页面中包含"runtime one", "runtime two"等内容的一个项目列表。每个项目都有类似文本"lorem ipsum"的副标题:
单击中的某一项将显示第二个页面,其中包含您单击项目的详细信息。这里您将看到完整的与您选择的项目关联的"lorem ipsum"文本。
停止运行应用程序并导航到MainPage.xaml。我们需要理解这个应用程序如何运作并确定我们是否可以将它应用到SoundBoard应用程序中。
在51至71行,项目列表由称为LongListSelector的控件实现。
注意一个含有绑定表达式的ItemsSource属性(54行)。在之前的课程中我简要地讨论过这种类型的绑定表达式。我们使用这种类型的表达式以将数据列表绑定到可视化控件。泛型列表中的每个项目,例如List<T>,将使用ItemTemplate(项模板)显示。在57至69行之间,您可以查看到为LongListSelector定义的项模板。ItemTemplate属性的类型是DataTemplate,这是一个简单的数据类型,它定义了数据对象的可视化结构。
在DataTemplate中,我们定义了集合中每个数据实例的可视化结构:一个包含两个TextBlock的StackPanel。
在每个TextBox中各有一个Text="{Binding LineOne}"和Text="{Binding LineTwo}"的属性值设置(分别在60行和63行)。它们将给定对象的属性绑定到控件的属性。我们待会儿将查看示例数据的类层次结构。首先让我们查看数据的来源,打开SampleData文件夹以显示MainViewModelSampleData.xaml文件:
如果您在解决方案资源管理器中打开该文件,您将会看到XML格式的文件,它包含了应用程序中的示例数据。注意每个ItemViewModel元素的属性:LineOne和LineTwo。它们与DataTemplate中绑定到每个TextBox的Text属性的实例属性的名称相匹配:
现在让我们在C#中查看用于构建这些数据的类。在ViewModels文件夹中有两个文件:
- ItemViewModel.cs
- MainViewModel.cs
ItemViewModel.cs文件包含我们绑定到的对象的类定义。在这里我们再次看到LineOne和LineTwo公共属性,以及私有字段定义和其他在本例中使用的属性:
请注意一些以前没有见过的内容,有一些额外的东西被添加到类的定义中,这将使它变得特别:
- 该类实现了INotifyPropertyChanged接口。
- 承诺实现接口的结果是有一个称为PropertyChanged的公共事件(和一个称为NotifyPropertyChanged的私有方法)被实现。
把这些内容添加到类的目的是为了实现“变更管理”的概念。每当该类的属性发生变化时,如果您查看一下每个属性的设置(“set”)部分(在上图中被折叠起来的部分),它将调用NotifyPropertyChanged()并传递它的名称。NotifyPropertyChanged()方法将调用PropertyChanged事件。当PropertyChanged()事件被触发时,任何侦听该事件的代码将被通知。
进一步让我们查看MainViewModel类:
它也:
- 实现了INotifyPropertyChanged和
- 公有的PropertyChanged事件
但是,它同时还有
3.一个公有的称为Items的ObservableCollection<ItemViewModel>
首先,回忆一下LongListSelector的ItemsSource属性被设置为"{Binding Items}"。是的,它指的就是这里的"Items"。这就是ItemViewModel对象实例的列表能够绑定到LongListSelector的原因。
Items属性是ObservableCollection<ItemViewModel>类型,作为一个可观察的集合,它知道集合中的实例提出的更改,然后它可以将这些更改报告给任何绑定到它的对象。
一个重要的问题是:为什么当集合中发生更改时其他代码需要被通知?
在本示例中,其它代码没有理由需要被通知,因为所有的示例数据都是“静态的”,它从一个静态的XML文件被加载,并且在应用程序运行过程中不会发生变化。
然而,如果我们想在应用程序中支持一项新的功能,即应用程序中的列表项持续不断被外部的来源(例如一个Web服务)更新。该web服务每30秒向每个ItemViewModel对象实例传递新的"lorem ipsum"文本,该项功能应该如何被实现呢?听起来有些笨,如果我们每30秒动态修改每个ItemViewModel实例中的数据,则应用程序的其余部分不需要进行任何修改。每个被更新的属性将会说:“嗨,我的值被修改了!”,然后整个对象实例将会说:“嗨,我被修改了!”。ObservableCollection将通知LongListSelector,然后它将神奇地在屏幕上被更新。
所以所有这些额外的代码:实现INotifyPropertyChanged接口,PropertyChanged事件以及所有调用NotifyPropertyChanged()的“设置”代码都是为了实现一个称为“可观测性(observability)”的功能和一个称为Model-View-ViewModel的软件开发模式。这些代码使得LongListSelector和其他控件在底层数据更新时自动更新显示的内容。
因为SoundBoard应用程序不需要“可观测性(observability)”,所以在本应用程序中不需要这些额外的代码。但是如果需要创建数据经常变化的这类应用程序,我一定会采用本项目中的方法。
好消息是您已经具备一个很好的模板,但是您还需要修改类和属性的名称以及数据加载的方式。但是模式已经被很好地实现了,并且可以作为模板来使用。
App.xaml.cs文件中的代码负责将数据从XML文件加载到数据模型的实例中。在构造函数中,MainViewModel的一个新的实例被创建,这个实例以App类的一个称为ViewModel的属性形式存在,并可以在整个应用程序中被访问。
随后在App.xaml.cs的Application_Activated事件中(可以参考注释以了解该事件何时被触发),如果App.ViewModel的IsDataLoaded为false,则会调用MainViewModel 类的LoadData()方法。您可以修改代码以便从web服务、本地数据库或XML文件检索数据。
在MainPage.xaml.cs文件的OnNavigatedTo()方法中将执行同样的判断。如果数据没有被加载,则对其进行加载。存在两个对LoadData()调用的原因是Windows Phone操作系统使用后退按钮在应用间导航造成的(以后会进行详述)。
通过以上分析希望您能够理解Windows Phone数据绑定应用程序模板是如何通过使用C#和Windows Phone运行时中称为“可观测性(observability)”的特性和MVVM设计模式实现了对数据的访问。
2. 理解Windows Phone透视应用程序项目模板的功能
虽然数据绑定项目模板提供了一些我们希望在SoundBoard应用程序中实现的功能,我们还需要提供浏览不同类别声音的方法。考虑到这一点,我们将查看Windows Phone透视应用程序模板。我们将放弃前一个应用程序并使用File | New | Project创建一个新的Windows Phone透视应用程序:
与本课前面一样:
- 确认您位于已安装| 模板| Visual C# | Windows Phone。
- 这次选择Windows Phone透视应用程序项目模板。
- 同样您不需要修改名称,我们将在以后删除这个项目。
- 单击确定。
同样这次我们希望立即运行应用程序以查看在未改动情况下它能实现的功能。应用程序第一眼看上去和之前的应用程序相同,但是请注意应用程序标题下方的区域:
您可以通过单击以在第一个和第二个视图(PivotItems)间进行滑动:
需要指出的是我们在使用示例数据,LongListSelector在两种情况下均绑定到同样的对象列表,但是在项目中我们创建了一个包含多个PivotItem(枢轴项)元素(我刚才称之为视图)的Pivot(枢轴控件),每个元素包含一个绑定到不同数据的LongListSelector:
- Pivot包含两个“页面”,更确切地说是“PivotItems”
- 这是第一个PivotItem
- 这是第二个PivotItem
- 每个PivotItem的内容与包含LongListSelector、数据模型等内容的数据绑定示例相对应。
我现在已经找到了解决问题的办法。我们可以使用Windows Phone数据透视应用程序模板创建声音类别。每类声音将基于DataTemplate进行呈现。我们需要创建一个数据模型,它将包括一些类别,每个类别又包含一组声音,声音将包含声音名称和播放wav文件的路径等信息。所以好消息是对接下来的工作我们有了一个明确的方向,只是需要进一步明确实现的细节。
回顾
综上所述,在本课中我们学习了数据绑定和透视应用程序模板的功能,它们几乎具备相同的功能。它们都将一个LongListSelector控件绑定到一个数据模型,该数据模型的数据来自一个XML文件。
上述模板不仅提供了在DataTemplate中将数据绑定到控件的功能,还提供了监视底层数据更改并自动在数据更改时更新用户界面的设计模式。虽然在我们的项目中并不需要这个功能,但是如果需要,我们可以应用上述模板中的这个简单的设计模式。最后,我们查看了在应用程序中使用Pivot控件创建pivot项的方法。