在 Windows Phone 上存储和检索 SharePoint 列表项
了解 Windows Phone 应用生命周期,以及如何本地存储网络数据。
不管是对整个应用程序还是对应用程序中的各网页或数据项,Windows Phone 应用程序开发中最重要的考虑因素之一是管理状态信息。 如果您正在开发 Windows Phone 应用程序,您必须考虑到应用程序的用户可能会丢失与网络资源(如 SharePoint 列表)的连接。 Windows Phone 应用程序的开发基础结构提供了用于处理应用程序生命周期中各阶段状态信息的机制。
重要
如果要开发适用于 Windows Phone 8 的应用,则必须使用 Visual Studio Express 2012 而不是 Visual Studio 2010 Express。 除开发环境外,本文中的其他所有信息都适用于创建 Windows Phone 8 和 Windows Phone 7 版应用。 > 有关详细信息,请参阅 如何:设置用于开发 SharePoint 移动应用的环境。
在 Windows Phone 上本地存储 SharePoint 列表数据
在 Windows Phone 上,一次只能运行一个应用。如果用户在手机上切换到另一个应用(例如,按手机上的“开始”按钮),当前正在运行的应用会停用(即 Windows Phone 开发领域的逻辑删除)。 如果用户切换回已停用的应用(按“返回”按钮),应用可以重新激活,但除非提供逻辑来处理应用生命周期内的应用状态信息,否则在从激活到停用再到重新激活的转换过程中,默认不会保留相应状态信息。 (若要详细了解 Windows Phone 应用的应用生命周期,请参阅 Windows Phone 的执行模型概述。)
For Windows Phone apps, the PhoneApplicationService class exposes standard life-cycle events that can be used to manage application state. In projects created from the Windows Phone SharePoint List Application template (as with projects created from all Silverlight for Windows Phone templates), these standard Windows Phone application life-cycle events are declared in the App.xaml file and associated with event handlers in the code-behind file, App.xaml.cs. The declarations in the App.xaml file for your SharePoint list apps should look like the following markup.
<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
<shell:PhoneApplicationService
Launching="Application_Launching" Closing="Application_Closing"Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>
在 App.xaml 文件中声明的 Application_Activated 和 Application_Deactivated 事件处理程序是在 App.xaml.cs 代码隐藏文件中实现的,该代码隐藏文件的默认逻辑是只要应用程序未终止即缓存应用程序状态信息以在手机应用程序中使用。 这些事件的处理程序的实现使用 PhoneApplicationService 类的 State 属性(提供对 Dictionary 对象的访问权限)来存储数据。 在此 State 属性中存储的数据是暂时的。 即,它在应用程序停用或逻辑删除时会保留,但在应用程序终止时不会保留。 在项目中处理应用程序生命周期事件时,要牢记当用户切换到另一个应用程序时,根据具体环境,停用的应用程序可能被 Windows Phone 操作系统终止。 手机上未保存到永久存储的数据会丢失,即使使用 PhoneApplicationService 的 State 属性将数据保存到临时存储也会丢失。
在从 SharePoint 列表中获取数据的 Windows Phone 应用程序中,手机会话过程中使用的数据当然可以在运行 SharePoint Server 的服务器中检索到(如果服务器可用)。 但是,由于服务覆盖范围的位置及其他因素的变化,Windows Phone 设备可能无法持续连接到 SharePoint Server。 为了在与运行 SharePoint Server 的服务器丢失连接时您的应用程序用户能够访问数据,或是仅为了不管服务器是否可用都将应用程序会话之间的数据存储到永久存储中,您可以使用 PhoneApplicationService 类的 Closing 和 Launching 事件。
这些事件的 Application_Launching 和 Application_Closing 处理程序在 App.xaml 中声明且在 App.xaml.cs 文件中定义,但它们均未实现。 要在应用程序终止环境中处理应用程序状态信息的存储和检索,您可以实现 Application_Closing 事件处理程序以将数据存储在为应用程序指定的独立存储中,以使应用程序会话之间的数据仍然存在,您还可以在启动新应用程序会话(即启动应用程序)时实现 Application_Launching 事件处理程序以从独立的存储中检索数据,即使连接不到作为原始数据源的运行 SharePoint Server 的服务器。
提示
在将数据保存到本地设备之前,应该对数据加密。 有关如何加密数据的详细信息,请参阅 如何:加密 Windows Phone 应用程序中的数据
实现用于存储和检索应用状态的事件处理程序的具体步骤
按照如何:创建 Windows Phone SharePoint 列表应用中的步骤,在 Visual Studio 中使用 Windows Phone SharePoint 列表应用程序模板创建 Windows Phone 应用。
在 解决方案资源管理器中,选择 App.xaml 文件。
按 F7 打开代码隐藏文件 (App.xaml.cs)进行编辑。
找到 Application_Launching 事件处理程序的(空)实现并将该事件处理程序替换为以下代码。
private void Application_Launching(object sender, LaunchingEventArgs e) { if (IsolatedStorageSettings.ApplicationSettings.Contains(DataProvider.ListTitle)) { App.MainViewModel = (ListViewModel)IsolatedStorageSettings.ApplicationSettings [DataProvider.ListTitle]; App.MainViewModel.Initialize(); } }
找到 Application_Closing 事件处理程序的(空)实现并将该事件处理程序替换为以下代码。
private void Application_Closing(object sender, ClosingEventArgs e) { if (IsolatedStorageSettings.ApplicationSettings.Contains(DataProvider.ListTitle)) { IsolatedStorageSettings.ApplicationSettings[DataProvider.ListTitle] = App.MainViewModel; } else { IsolatedStorageSettings.ApplicationSettings.Add(DataProvider.ListTitle, App.MainViewModel); } IsolatedStorageSettings.ApplicationSettings.Save(); }
保存文件。
有了这些实现,请运行应用,使用运行 SharePoint Server 的服务器中的数据初始化应用中的主 ViewModel。 在手机上退出应用(按“返回”按钮,返回应用的第一页),触发 Application_Closing 事件。 如果随后在未连接到服务器的情况下运行应用,则会检索并初始化保存到 Application_Closing 事件) 中 IsolatedStorageSettingsDictionary 对象 (的 ViewModel。 此时,应用的列表表单 (List.xaml) 会显示在上一应用会话中保存到独立存储的 SharePoint 列表项。
实现列表项离线编辑机制
如果您按照上一部分中的过程在应用程序中实现 Closing 和 Launching 事件的处理程序,则当连接可用时从服务器检索的 SharePoint 列表数据可以显示在您的应用程序中,即使在应用程序的后续会话中丢失与服务器的连接也会如此,因为列表项是从手机上的永久存储中检索的。 然而,基于上一部分中的实现,以这种方式脱机显示的列表项无法编辑和保存到服务器,除非恢复连接。 在以下过程中,您要向您的应用程序添加一个机制,以便在连接不可用时本地存储编辑后的列表项。 与服务器的连接再次可用时,您可以检索这些编辑后的列表项并将您的更改保存回服务器。
对于本部分中的过程,我们假设您在使用 Windows Phone SharePoint 列表应用程序模板创建的 Windows Phone 应用程序项目环境中工作,而且您的应用程序基于使用服务器上的自定义列表模板创建的"产品订单数"列表,并且包含表 1 中所示的列和字段类型。
表 1. “产品订单数”列表示例
Column | 类型 | 必需 |
---|---|---|
产品(例如,标题) | 单行文本(文本) | 是 |
说明 | 单行文本(文本) | 否 |
数量 | 数字 | 是 |
订单日期 | 日期和时间 (Datetime) | 否 |
完成时间 | 日期和时间 (Datetime) | 否 |
联系人电话 | 单行文本(文本) | 否 |
实现用于支持脱机编辑项的类
从基于表 1 表示的"产品订单数"列表创建的 Visual Studio 项目开始,在"解决方案资源管理器"中,选择表示该项目的节点(例如,SPListAppLocalStorage)。
在"项目"菜单中,选择"添加类"。
"添加新项"对话框出现,其中 C#"类"模板处于选中状态。
将类文件命名为 DraftItemStore.cs,然后选择"添加"。
类文件将添加到项目中并打开以供编辑。
用以下代码替换类文件的内容。
using System; using System.Net; using System.Windows; using System.Collections.Generic; using System.IO.IsolatedStorage; namespace SPListAppLocalStorage // Based on project name by default. { public class DraftItemStore { const string DraftsKey = "Drafts"; public static void AddDraftItem(string id, EditItemViewModel model) { Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection(); draftCollection[id] = model; SaveDrafts(draftCollection); } public static void RemoveDraftItem(string id) { Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection(); draftCollection.Remove(id); SaveDrafts(draftCollection); } public static void SaveDrafts(Dictionary<string, EditItemViewModel> draft) { if (IsolatedStorageSettings.ApplicationSettings.Contains(DraftsKey)) { IsolatedStorageSettings.ApplicationSettings[DraftsKey] = draft; } else { IsolatedStorageSettings.ApplicationSettings.Add(DraftsKey, draft); } } public static List<EditItemViewModel> Drafts { get { Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection(); List<EditItemViewModel> modelCollection = new List<EditItemViewModel>(); foreach (KeyValuePair<string, EditItemViewModel> entry in draftCollection) { modelCollection.Add(entry.Value); } return modelCollection; } } public static Dictionary<string, EditItemViewModel> GetDraftItemCollection() { Dictionary<string, EditItemViewModel> draftCollection = null; if (IsolatedStorageSettings.ApplicationSettings.Contains(DraftsKey)) draftCollection = (Dictionary<string, EditItemViewModel>)IsolatedStorageSettings.ApplicationSettings[DraftsKey]; if (draftCollection == null) draftCollection = new Dictionary<string, EditItemViewModel>(); return draftCollection; } public static EditItemViewModel GetDraftItemById(string id) { Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection(); return !draftCollection.ContainsKey(id) ? null : draftCollection[id]; } } }
此代码中指定的命名空间基于项目的名称(在本例中为 SPListAppLocalStorage)。 您可能希望基于您的项目名称指定一个不同的命名空间。
保存该文件。
EditItemViewModel 类的一个特定实例表示手机中正在编辑的一个 SharePoint 列表项。 您可以考虑将编辑过的列表项视为“草稿项”,然后将对项目的更改保存到服务器。 在此类中的代码中,AddDraftItem 方法将 EditItemViewModel 类(即草稿项目)的特定实例作为一个值添加到 Dictionary 对象,从而将 Dictionary 中的EditItemViewModel 与基于给定列表项的标识符的一个键相关联。 (SharePoint Server 将标识符分配给列表中的每个项。在基于 Windows Phone SharePoint 列表应用程序模板的项目中,该标识符存储在给定 ViewModel 类的 ID 属性中,例如 EditItemViewModel 或 DisplayItemViewModel,它表示列表项。) RemoveDraftItem 方法基于指定的标识符从 Dictionary 对象中删除 EditItemViewModel。 这两个方法均使用 GetDraftItemCollection 方法从独立的存储中检索包含 EditItemViewModel 对象的 Dictionary 对象,而且均使用 SaveDrafts 方法将修改后的 Dictionary 对象(在其中添加或删除了一个草稿项)保存回独立的存储中。 GetDraftItemCollection 方法首先确定“草稿”Dictionary 对象是否已保存到独立存储中。 如果是,该方法将返回该 Dictionary 对象;否则,此方法将初始化并返回一个新的 Dictionary 对象。 类的 Drafts 属性通过返回一个列表 (提供对草稿项 字典 的访问,该列表 (,即基于 List<T> 泛型) 作为 EditItemViewModel 对象的草稿项的对象。 GetDraftItemById 方法基于指定的标识符值从 Dictionary 对象返回一个给定的草稿项。
现在,您可以将元素添加到手机应用程序的用户界面并将它们配置为使用 DraftItemStore 类来脱机编辑列表项。 在下列过程中,您将:
- 添加并配置一个 Windows Phone 页来显示作为草稿项保存在手机独立存储中的所有列表项。
- 添加并配置另一个页面,它绑定到 EditItemViewModel,用于编辑单个草稿项,类似于列表项的"编辑"窗体 (EditForm.xaml)。
- 将 SaveAsDraft 方法添加到 EditItemViewModel 类,该类执行在前面过程中实现的 DraftItemStore 类的 AddDraftItem 方法。
- 将一个 ApplicationBar 按钮添加到 EditForm.xaml 文件来调用 SaveAsDraft 方法。
- 将一个 ApplicationBar 按钮添加到 List.xaml 文件以导航到显示所有保存为草稿的列表项的页面。
添加用于显示手机上保存的所有草稿项的页面
在"解决方案资源管理器"中,选择"视图"文件夹。
在"项目"菜单上,选择"添加新项"。
将打开"添加新项"对话框。
在"添加新项"对话框中,在"Visual C#"节点下,选择"Silverlight for Windows Phone"节点。
在"模板"窗格中,选择"Windows Phone 纵向页面"模板。
将文件命名为 Drafts.xaml,然后选择"添加"。
该文件将添加到项目的"视图"节点下并打开以供编辑。
在设计器的 XAML 窗格中,将文件内容替换为以下 XAML。
<phone:PhoneApplicationPage x:Class="SPListAppLocalStorage.Views.Drafts" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="Product Orders" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="Draft Items" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ListBox x:Name="lstBoxDraftItems" ItemsSource="{Binding}" SelectionChanged="lstBoxDraftItems_SelectionChanged"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding [Title]}" Style=" {StaticResource PhoneTextTitle2Style}"></TextBlock> <TextBlock Text="{Binding [Description]}" Style=" {StaticResource PhoneTextNormalStyle}"></TextBlock> <TextBlock Text="{Binding [Contact_x0020_Number]}" Style=" {StaticResource PhoneTextNormalStyle}"></TextBlock> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton x:Name="btnCancel" IconUri="/Images/appbar.cancel.rest.png" Text="Cancel" Click="OnCancelButtonClick" /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> </phone:PhoneApplicationPage>
此代码中命名空间指定
<x:Class>
(“SPListAppLocalStorage.Views.Drafts”) 的值因项目名称而异。在“解决方案资源管理器”中选择“Drafts.xaml”文件后,按 F7 打开关联的代码隐藏文件“Drafts.xaml.cs”以供编辑。
用以下代码替换文件的内容。
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; namespace SPListAppLocalStorage.Views { public partial class Drafts : PhoneApplicationPage { public Drafts() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Drafts_Loaded); } private void lstBoxDraftItems_SelectionChanged(object sender, SelectionChangedEventArgs e) { ListBox lstBox = sender as ListBox; if (lstBox.SelectedIndex == -1) return; EditItemViewModel selectedDraftItem = lstBox.SelectedItem as EditItemViewModel; NavigationService.Navigate(new Uri(string.Format("/Views/DraftItemEditForm.xaml?ID={0}", selectedDraftItem.ID), UriKind.Relative)); lstBox.SelectedIndex = -1; } void Drafts_Loaded(object sender, RoutedEventArgs e) { this.DataContext = DraftItemStore.Drafts; } private void OnCancelButtonClick(object sender, EventArgs e) { // Navigate back to initial List View form. NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative)); } } }
保存文件。
添加用于编辑单个草稿项的页面
在"解决方案资源管理器"中,选择"视图"文件夹。
在"项目"菜单上,选择"添加新项"。
将打开"添加新项"对话框。
在"添加新项"对话框中,在"Visual C#"节点下,选择"Silverlight for Windows Phone"节点。
在"模板"窗格中,选择"Windows Phone 纵向页面"模板。
将文件命名为 DraftItemEditForm.xaml,然后选择"添加"。
该文件将添加到项目的"视图"节点下并打开以供编辑。
在设计器的 XAML 窗格中,将文件内容替换为以下 XAML。
<phone:PhoneApplicationPage x:Class="SPListAppLocalStorage.DraftItemEditForm" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True" x:Name="DraftItemEditPage"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly= Microsoft.Phone.Controls"> <StackPanel> <ProgressBar Background="Red" x:Name="progressBar" Opacity="1" HorizontalAlignment="Center" VerticalAlignment="Top" Height="15" Width="470" IsIndeterminate="{Binding IsBusy}" Visibility="{Binding ShowIfBusy}" /> <ScrollViewer HorizontalScrollBarVisibility="Auto" Height="700"> <Grid x:Name="ContentPanel" Width="470"> <StackPanel Margin="0,5,0,5"> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Product*</TextBlock> <TextBox Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtTitle" Text="{Binding [Title], Mode=TwoWay,ValidatesOnNotifyDataErrors=True,NotifyOnValidationError=True}" TextWrapping="Wrap" /> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Description</TextBlock> <TextBox Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtDescription" Text="{Binding [Description], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" TextWrapping="Wrap" /> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}"> Product Category</TextBlock> <ListBox MaxHeight="400" Width="Auto" x:Name="lstBoxProduct_x0020_Category" ItemsSource="{Binding [Product_x0020_Category]}"> <ListBox.ItemTemplate> <DataTemplate> <RadioButton FontSize="{StaticResource PhoneFontSizeNormal}" HorizontalAlignment="Left" GroupName="Product_x0020_Category" Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Quantity*</TextBlock> <TextBox Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtQuantity" Text="{Binding [Quantity], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" TextWrapping="Wrap" /> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Order Date</TextBlock> <TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtOrder_x0020_Date" Text="{Binding [Order_x0020_Date], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" TextWrapping="Wrap" /> <TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding DateTimeFormat}" /> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Fulfillment Date</TextBlock> <TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtFulfillment_x0020_Date" Text="{Binding [Fulfillment_x0020_Date], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" TextWrapping="Wrap" /> <TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding DateTimeFormat}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Rush :</TextBlock> <CheckBox Name="txtRush" FontSize="{StaticResource PhoneFontSizeNormal}" HorizontalAlignment="Left" IsChecked="{Binding [Rush], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" /> </StackPanel> <StackPanel Orientation="Vertical" Margin="0,5,0,5"> <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Contact Number</TextBlock> <TextBox Style="{StaticResource TextValidationTemplate}" FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left" Name="txtContact_x0020_Number" Text="{Binding [Contact_x0020_Number], Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" TextWrapping="Wrap" /> </StackPanel> </StackPanel> </Grid> </ScrollViewer> </StackPanel> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton x:Name="btnSubmit" IconUri="/Images/appbar.save.rest.png" Text="Submit" Click="OnSubmitButtonClick"/> <shell:ApplicationBarIconButton x:Name="btnBack" IconUri="/Images/appbar.back.rest.png" Text="Back to List" Click="OnBackButtonClick"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> </phone:PhoneApplicationPage>
用于定义此页面的 XAML 类似于 EditForm.xaml 文件的 XAML 。 可以复制 EditForm.xaml 文件以用作 DraftItemEditForm.xaml 的基础,并按照此标记中的指示对文件进行修改。
在解决方案资源管理器中选择 DraftItemEditForm.xaml 文件后,按 F7 打开关联的代码隐藏文件 DraftItemEditForm.xaml.cs进行编辑。
用以下代码替换文件的内容。
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.SharePoint.Client; using Microsoft.Phone.Tasks; using System.Device.Location; using Microsoft.Phone.Shell; using Microsoft.SharePoint.Phone.Application; namespace SPListAppLocalStorage { public partial class DraftItemEditForm : PhoneApplicationPage { EditItemViewModel viewModel; /// <summary> /// Constructor for Draft Item Edit Form. /// </summary> public DraftItemEditForm() { InitializeComponent(); } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { // Include initialization of ViewModel here rather than in constructor to be able to use QueryString value. if (viewModel == null) { viewModel = DraftItemStore.GetDraftItemById(NavigationContext.QueryString["ID"].ToString()); } viewModel.Initialize(); this.DataContext = viewModel; base.OnNavigatedTo(e); viewModel.ItemUpdated += new EventHandler<ItemUpdatedEventArgs>(OnItemUpdated); } protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedFrom(e); viewModel.ItemUpdated -= new EventHandler<ItemUpdatedEventArgs>(OnItemUpdated); } private void OnViewModelInitialization(object sender, InitializationCompletedEventArgs e) { this.Dispatcher.BeginInvoke(() => { // If initialization has failed show error message and return. if (e.Error != null) { MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK); return; } // Set Page's DataContext to current ViewModel instance. this.DataContext = (sender as EditItemViewModel); }); } private void OnCancelButtonClick(object sender, EventArgs e) { NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative)); } private void OnSubmitButtonClick(object sender, EventArgs e) { viewModel.UpdateItem(); } private void OnItemUpdated(object sender, ItemUpdatedEventArgs e) { this.Dispatcher.BeginInvoke(() => { if (e.Error != null) { MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK); return; } // Remove Draft Item from local storage if update to server succeeds. DraftItemStore.RemoveDraftItem(viewModel.ID.ToString()); this.NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative)); }); } private void OnBackButtonClick(object sender, EventArgs e) { NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative)); } } }
您可以看到,此文件中使用的命名空间基于项目名称 (SPListAppLocalStorage)。
在 DraftItemEditForm.xaml 文件中声明的“ApplicationBar”按钮 (btnBack) ,将appbar.back.rest.png图像添加到项目中。 在"解决方案资源管理器"中,选择项目中的"图像"文件夹节点。
在"项目"菜单中,选择"添加现有项"。
在打开的浏览器中,导航到包含由 Windows Phone SDK 7.1 安装的标准 Windows Phone 图标图像的文件夹中。
注意
具有浅色前景和深色背景的图像处于
%PROGRAMFILES%(x86)\\Microsoft SDKs\\Windows Phone\\v7.1\\Icons\\dark
SDK 的标准安装中。选择名为 appbar.back.rest.png的图像文件,然后选择 “添加”。 图像会添加到项目的Images节点下。
在"解决方案资源管理器"中,选择您刚添加的图像文件,并在该文件的"属性窗口"中,将图像文件的"生成操作"属性设置为"内容",并将"复制到输出目录"属性设置为"如果较新则复制"[###Copy if newer]。
保存文件。
将 ApplicationBar 按钮添加到"编辑"窗体以将项保存为草稿
在“解决方案资源管理器”中,选择项目中“ViewModels”节点下的EditItemViewModel.cs文件。 按 F7 打开文件进行编辑。
在用于实现 EditItemViewModel 类的代码块(由成对的括号限定)内,将以下公用方法添加到文件。
public void SaveAsDraft() { DraftItemStore.AddDraftItem(this.ID.ToString(), this); }
在"解决方案资源管理器"中,在项目中的"视图节点下,双击 EditForm.xaml 文件。
文件在设计器中打开以供编辑。
在设计器的 XAML 窗格中,除了) 现有的“提交”和“取消”
<shell:ApplicationBar>
按钮外,向标记 (添加另一个按钮,如以下 XAML 所示。<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton x:Name="btnSubmit" IconUri="/Images/appbar.save.rest.png" Text="Submit" Click="OnBtnSubmitClick"/> <shell:ApplicationBarIconButton x:Name="btnSaveDraft" IconUri="/Images/appbar.save.rest.png" Text="Save Draft" Click="OnSaveDraftButtonClick"/> <shell:ApplicationBarIconButton x:Name="btnCancel" IconUri="/Images/appbar.cancel.rest.png" Text="Cancel" Click="OnCancelButtonClick"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>
在 解决方案资源管理器中选择 EditForm.xaml 文件后,按 F7 打开关联的代码隐藏文件 (EditForm.xaml.cs)进行编辑。
在用于实现 EditForm 分部类的代码块(由成对的括号限定)内,将以下事件处理程序添加到文件。
private void OnSaveDraftButtonClick(object sender, EventArgs e) { viewModel.SaveAsDraft(); }
保存文件。
将 ApplicationBar 按钮添加到列表视图窗体以显示所有草稿项
在"解决方案资源管理器"中的"视图"节点下,双击 List.xaml 文件。
文件在设计器中打开以供编辑。
在设计器的 XAML 窗格中,除了) 现有的“新建”和“刷新”按钮<外, (shell:ApplicationBar> 标记中添加另一个按钮,如以下 XAML 标记所示。
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton x:Name="btnNew" IconUri="/Images/appbar.new.rest.png" Text="New" Click="OnNewButtonClick"/> <shell:ApplicationBarIconButton x:Name="btnRefresh" IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/> <shell:ApplicationBarIconButton x:Name="btnDrafts" IconUri="/Images/appbar.folder.rest.png" Text="View Drafts" IsEnabled="True" Click="OnDraftsButtonClick"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>
将"草稿"[###Drafts]按钮的图标图像添加到您的项目中。 在"解决方案资源管理器"中,选择项目中的"图像"文件夹节点。
在"项目"菜单中,选择"添加现有项"。
在打开的浏览器中,导航到包含由 Windows Phone SDK 7.1 安装的标准 Windows Phone 图标图像的文件夹中。
注意
具有浅色前景和深色背景的图像处于
%PROGRAMFILES%(x86)\\Microsoft SDKs\\Windows Phone\\v7.1\\Icons\\dark
SDK 的标准安装中。依次选择名为“appbar.folder.rest.png”的图像文件和“添加”。
图像将添加到项目中的Images节点下。
在"解决方案资源管理器"中,选择您刚添加的图像文件,并在"属性窗口"中将图像文件的"生成操作"属性设置为"内容",将"复制到输出目录"[###Copy to Output Directory]属性设置为"如果较新则复制"。
在 “解决方案资源管理器”中,选择“ 视图 ”节点下的 List.xaml 文件,然后按 F7。 将打开关联的代码隐藏文件 (List.xaml.cs)进行编辑。
将以下事件处理程序添加到该文件中用于实现 ListForm 分部类的代码块(由成对的括号限定)内。
private void OnDraftsButtonClick(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Views/Drafts.xaml", UriKind.Relative));
}
- 保存解决方案中的所有文件,然后按 F6 编译解决方案。
如果您启动该项目并将其部署到一个 Windows Phone Emulator,您会看到列表窗体的 ApplicationBar 上有个“视图草稿”按钮(图 1),它可以显示以草稿形式存储的所有列表项。
图 1. 带有“视图草稿”按钮的修改后的列表窗体
最初,由于没有保存草稿,显示草稿的页面将为空。 从"列表"窗体(用于显示一个项的"显示"窗体 (DisplayForm.xaml))中选择一个项,然后选择"编辑"按钮以显示"编辑"窗体。 如果您丢失与 SharePoint Server 的连接,则可以在"编辑"窗体中选择"保存草稿"按钮(图 2),以将您对列表项所做的任何更改保存到独立存储中。
图 2. 带有“保存草稿”按钮的修改后的“编辑”窗体
当服务器再次变为可用时,您可以选择"列表"窗体中的"查看草稿"[###View Drafts]按钮来显示"草稿"页(图 3)。
图 3. 用于显示作为草稿保存到独立存储中的项的“草稿”页
如果您在"草稿"页上选择一个项,会显示"草稿项编辑"窗体 (DraftItemEditForm.xaml)(图 4),您可以对其进行任何其他更改,然后单击"提交"按钮以将编辑后的项保存到服务器。 此时,该项会从独立存储中删除,因为如果它经修改后保存到服务器中,就不再被视为草稿项了。
图 4. “草稿项编辑”窗体
请注意"草稿项编辑"窗体(图 4)与此应用程序中的标准"编辑"窗体(图 2)之间的相似性。 草稿项的编辑体验应该与在"编辑"窗体环境下的项的编辑体验大致相同。