Developing Windows Phone 7 Database Applications

從Windows Mobile 6.5到Windows Phone 7,Microsoft做了一個相當重大的決定,選擇將Windows Phone 7視為另一個手機作業系統的起點

 

Developing Windows Phone 7 Database Applications
 
 
 
/黃忠成
 
 
       從Windows Mobile 6.5到Windows Phone 7,Microsoft做了一個相當重大的決定,選擇將Windows Phone 7視為另一個手機作業系統的起點,這意味著,
Windows Phone 7與Windows Mobile 6.5完全沒有關係,也不是Windows Mobile 6.5的改良,舊有的Windows Mbile 6.5應用程式及設計概念,也不再是
Windows Phone 7的包袱,它是一個全新的手機作業系統。
 
     對於Windows Mobile系的手機用戶而言,這個決定有著正反兩面的含意,雖然Windows Mobile這些年來遭受許多批評,有人說其過於緩慢、龐大,
也有人提及應用程式效能不好調校,但其與Windows 的相容程度,是至今用戶們仍然愛用的原因。
 
     到了Windows Phone 7,由於市場上尚未看到實機,無法對許多用戶關心的Windows相容性做出評論,但其先天的應用程式開發架構,已經可以
看出Windows Phone 7未來的走向,Windows Phone 7支援兩種型態的應用程式開發架構,一個是以Silverlight為主,另一個則是以XNA為主,兩者
皆以針對Windows Phone 7所設計的.NET Framework為基底。
 
     那原生(Native)應用程式呢?目前Windows Phone 7並不允許一般開發者使用Native應用程式,也就是說,開發者將無法以C++開發一個應用程式,
然後令其執行於Windows Phone 7上,但如果是OEM廠商,那麼在得到Microsoft支援及認可的情況下,還是能夠使用Native應用程式。
 
     OK,那麼以.NET Compact Framework所開發的程式呢?答案是類似的,Windows Phone 7是一個以專屬於Windows Phone 7的.NET Framework
為主的應用程式架構,所以假如原先的應用程式是以.NET Compact Framework所撰寫的,那麼就得選擇改寫為XNA or Silverlight。
 
     未來,Windows Phone 7上的應用程式將分成兩個走向,一個是以Silverlight所開發的商業型應用程式,這類程式著重在功能面,例如以資料庫為主的應用。
另一個則是手機遊戲,由於使用與XBOX 360相同的XNA架構,未來許多XBOX Live的遊戲都會出現在Windows Phone 7上。 
 
    當然,這個分界並不是絕對的,用Silverlight也可以撰寫遊戲,只是相對於使用XNA而言,少了移植性,畢竟遊戲能多在一個平台上銷售,那麼就會多一些銷量,
使用XNA開發的話,未來可以移植到Windows 及XBOX 360上。
 
PS:技術上來說,Windows Phone 7核心仍然是使用Windows CE 6.5,不過僅止有內核部份而已。
 
 
First Application
 
 
       本文的重點放在Silverlight應用程式開發上,在開始之前,得先準備好Windows Phone 7開發的環境,需求如下
 

            (包含了Visual Studio 2010 Express for Windows PhoneExpression Blend for Windows Phone等工具)

            (此版開發工具也支援RTM版的Visual Studio 2010,也就是裝好後,你可以在Visual Studio 2010中開發Windows Phone 7應用程式,不需使用Express版的
            Visual Studio 2010,前提是已安裝的Visual Studio 2010得是英文的,如果是中文版的,那麼你必須自行將
            Visual Studio 2010\IDE\ProjectTemplates\CSharp\Silverlight for Windows Phone\1033
            的檔案複製到users\My Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual C#\Silverlight for Windows Phone目錄下,詳見Will保哥的Blog)
 
一切無誤的話,那麼就能在Visual Studio 2010 Express for Windows Phone看到下圖的專案類型。 
1
 
 
點選Windows Phone Application後即可建立Silverlight For Windows Phone 7的專案,之後就如同開發Silverlight應用程式一樣簡單,只是畫面小了些罷了。 
2
 
 
照往例,放個Button控制項到上面,然後顯示Hello World的訊息框。 
3
 
MainPage.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 WindowsPhoneApplication3
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Hello World");
        }
    }
}
 
 
按下F5即可執行,此時模擬器會啟動,而程式會被部署到模擬器內並執行,按下Button後即跳出訊息框。
 
4
 
 
 
 
The Navigation Of Phone Application
 
 
       那如果有多個XAML,然後想在各個XAML間切換時,在Windows Phone 7中又該如何做呢?很簡單,跟Silverlight 4的
Navigation Application一樣的寫法。
       於此專案中加入一個新的Page。
 
圖5
 
 修改其Page Title。

 

Page1.xaml
<phone:PhoneApplicationPage
    x:Class="WindowsPhoneApplication3.Page1"
    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="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">
 
    <!--LayoutRoot contains the root grid where all other 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="24,24,0,12">
            <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="Detail Page" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentGrid" Grid.Row="1">
        </Grid>
    </Grid>
 
</phone:PhoneApplicationPage>
 
最後只要修改MainPage.xaml.cs中的button_click事件,透過NavigationService來進行轉換頁面即可。
 
MainPage.xaml.cs
private void button1_Click(object sender, RoutedEventArgs e)
{
            NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative));
}
 
注意,Navigate函式不支援絕對路徑,所以不能省略UriKind.Relative參數。
 
圖6
 
按下下方的後退按紐,即可回到MainPage。
 
 
Consuming WCF Service
 
 
    Silverlight for Windows Phone 7的應用程式也能取用WCF Service,不過此處會遭遇到一個問題,那就是Visual Studio 2010 Express for Windows Phone並無法建立
ASP.NET Web Application,也無法建立WCF Service,這必須要用完整版本的Visual Studio 2010才能辦到,因此,由此節開始將使用完整版本的Visual Studio 2010 
    首先建立一個Phone Application專案,接著建立ASP.NET Web 空白應用程式(記得選擇加入至方案)
7
 
 然後於ASP.NET Web專案中加入WCF Service
 
8
 
修改Service1.csIService.cs如下。
 
IService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
 
namespace WebApplication1
{
   [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string Hello(string name);
    }
}_
Service.svc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
 
namespace WebApplication1
{
    public class Service1 : IService1
    {
        public string Hello(string name)
        {
            return "Hello " + name;
        }
    }
}
 
如同一般Silverlight應用程式一樣,透過新增服務參考來取得Service Reference
 
9
 
最後放置一個ButtonPhone Application的頁面上,然後撰寫以下的事件處理函式。
 
MainPage.xaml.cs
private void button1_Click(object sender, RoutedEventArgs e)
{
            ServiceReference1.Service1Client client =
new ServiceReference1.Service1Client();
            client.HelloCompleted += (s, args) =>
                {
                    MessageBox.Show(args.Result);
                };
            client.HelloAsync("code6421");
}
 
執行並按下按紐,即可呼叫WCF Service
 
10
 
 
 
 
Creating Phone List Application
  
     除了簡單的Phone Application專案範本外,Windows Phone 7 SDK也提供了Phone List Application專案範本,這個範本預設會放置一個
ListBox控制項在頁面上,並使用MVVM Pattern來處理資料及顯示。
 
11
 
當然,這個預設的Template中資料是假造的,其只是在MainViewModel.cs中以程式添加幾列資料而已,實際專案中多半是透過WCF Service來取得資料列。
 
 
 
Consuming WCF RIA Service – SOAP Version
 
 
      一想到要透過WCF Service來取得資料,自然而然便會想到WCF Data ServiceWCF RIA Service,以Silverlight來說,WCF RIA Service可以說是相當的好用,
那麼Windows Phone 7上的Silverlight也能使用WCF RIA Service嗎?答案是肯定的,但是由於目前工具尚未完善,所以得動些手腳就是了。 
      開始之前,得先安裝好RIA Service Toolkit
      接著建立一個Phone List Application,然後再建立一個ASP.NET Web空白應用程式專案,然後加入一個LINQ To SQL類別。
12
 
於內加入北風資料庫的Customers資料表。
 
13
 
編譯後,再加入Domain Service
 
14
15
 
挑選要expose的資料表後,按下OK後重新編譯。
原本在Silverlight 4中,只要啟用支援RIA Service,那麼Visual Studio 2010便會自動產生Proxy Code,但目前Windows Phone 7 SDK並未支援此特色,
所以得動點手腳,讓Domain Serviceexpose一個SOAP Endpoint,請修改web.config檔案。
 
web.config
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
 <configSections>
    <sectionGroupname="system.serviceModel">
      <sectionname="domainServices"type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"allowDefinition="MachineToApplication"requirePermission="false" />
    </sectionGroup>
 </configSections>
 <system.webServer>
        <modulesrunAllManagedModulesForAllRequests="true">
            <addname="DomainServiceModule"preCondition="managedHandler"
                type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </modules>
        <validationvalidateIntegratedModeConfiguration="false" />
    </system.webServer>
    <connectionStrings>
        <addname="NorthwindConnectionString"connectionString="Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password="
            providerName="System.Data.SqlClient" />
    </connectionStrings>
    <system.web>
        <httpModules>
            <addname="DomainServiceModule"type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </httpModules>
        <compilationdebug="true"targetFramework="4.0" />
    </system.web>
 
    <system.serviceModel>
      <domainServices>
        <endpoints>
          <addname="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        </endpoints>
      </domainServices>
      <serviceHostingEnvironmentaspNetCompatibilityEnabled="true"
            multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
</configuration>
 
然後於Web Application專案中添加RIA Service Toolkit中的Microsfot.ServiceModel.DomainServices.Hosting.dll Reference,此檔案位於
Program Files\Microsoft SDKs\RIA Service\v1.0\Toolkit\Libraries\Server目錄中。
 
16
17
 
完成後重新編譯應用程式,此時應可透過http://localhost:<port>/<Web Application Project Name>-<DomainService Name>.svc?wsdl
來取得RIA ServiceWSDL文件。
 
18
 
測試可正確取得WSDL文件後,便可透過新增服務參考,將RIA Service引用於Phone List Application專案中。
 
19
 
接下來的動作,就是修改原本的ViewModel,改為透過RIA Service來取得資料,請先刪除ViewModels下的ItemViewModel.cs
然後修改MainViewModel.cs為如下所示。
 
MainViewModel.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
 
 
namespace WindowsPhoneListApplication1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        internal ServiceReference1.NorthwindSvcSoapClient _client = null;
        public MainViewModel()
        {
            Items = new ObservableCollection<ServiceReference1.Customers>(); // default.
            _client = new ServiceReference1.NorthwindSvcSoapClient();
            _client.GetCustomersCompleted += (s, args) =>
            {
                foreach (var item in args.Result.RootResults)
                {
                    Items.Add(item);
                }
            };
            _client.GetCustomersAsync();
        }
 
        public ObservableCollection<ServiceReference1.Customers> Items
{ get; private set; }
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
 
如果於產生Service Reference時有一個以上的錯誤(一般情況下,應該只會顯示一個警告),那麼就代表著遇到討厭的Bug
重開Visual Studio 2010可以解決此情況。
完成MainViewModel的修改後,接著得修改MainPage.xaml,主要是修改Binding的目標。
 
MainPage.xaml
<phone:PhoneApplicationPage
    x:Class="WindowsPhoneListApplication1.MainPage"
    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:DesignWidth="480" d:DesignHeight="768"
    shell:SystemTray.IsVisible="True">
 
    <!--Data context is set to sample data above and LayoutRoot contains the root grid where all other 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="24,24,0,12">
            <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="ListTitle" Text="Customers " Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel contains ListBox and ListBox ItemTemplate. Place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1">
            <ListBox x:Name="MainListBox" ItemsSource="{Binding Items}" SelectionChanged="MainListBox_SelectionChanged">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
                            <Image x:Name="ItemImage" Source="/WindowsPhoneListApplication1;component/Images/ArrowImg.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
                            <StackPanel>
                                <TextBlock x:Name="ItemText" Text="{Binding CustomerID}" Margin="-2,-13,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                <TextBlock x:Name="DetailsText" Text="{Binding CompanyName}" Margin="0,-6,0,3" Style="{StaticResource PhoneTextSubtleStyle}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>
 
接著修改DetailPage.xaml
 
DetailPage.xaml
<phone:PhoneApplicationPage
    x:Class="WindowsPhoneListApplication1.DetailsPage"
    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:DesignWidth="480" d:DesignHeight="768"
    shell:SystemTray.IsVisible="True">
 
    <!--Data context is set to sample data above and first item in sample data collection below and LayoutRoot contains the root grid where all other page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{Binding Items[0]}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!--TitleGrid is the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
            <TextBlock x:Name="PageTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="ListTitle" Text="{Binding CustomerID}" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
 
        </StackPanel>
 
        <!--ContentPanel contains details text. Place additional content here-->
        <StackPanel x:Name="Details" Orientation="Vertical" Margin="24,87,76,70" Grid.Row="1" >
            <TextBlock x:Name="lbCompanyName" Text="Company Name" FontSize="36" ></TextBlock>
            <TextBlock x:Name="txtCompanyName" Text="{Binding CompanyName,Mode=TwoWay}" Height="80" FontSize="36"/>
            <TextBlock x:Name="lbContactName" Text="Contact Name" FontSize="36"></TextBlock>
            <TextBlock x:Name="txtContactName" Text="{Binding ContactName,Mode=TwoWay}"  Height="80"  FontSize="36"/>
            <TextBlock x:Name="lbPhone" Text="Phone"  FontSize="36"></TextBlock>
            <TextBlock x:Name="txtPhone" Text="{Binding Phone,Mode=TwoWay}"  Height="80" FontSize="36" />
        </StackPanel>
    </Grid>
</phone:PhoneApplicationPage>
 
完成後,請刪除SamplesData目錄下的.xml檔案後執行應用程式,即可看到圖20的畫面。
 
20
 
按下其中一筆資料後,即轉換至DetailPage
 
21
 
那如果要添加資料的更新機制呢?這簡單,先將DetailPage.xaml中的TextBlock改為TextBox,再加上一個Button來更新資料。
 
DetailPage.xaml
<phone:PhoneApplicationPage
    x:Class="WindowsPhoneListApplication1.DetailsPage"
    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:DesignWidth="480" d:DesignHeight="768"
    shell:SystemTray.IsVisible="True">
 
    <!--Data context is set to sample data above and first item in sample data collection below and LayoutRoot contains the root grid where all other page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{Binding Items[0]}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!--TitleGrid is the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
            <TextBlock x:Name="PageTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="ListTitle" Text="{Binding CustomerID}" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
 
        </StackPanel>
 
        <!--ContentPanel contains details text. Place additional content here-->
        <StackPanel x:Name="Details" Orientation="Vertical" Margin="24,87,76,70" Grid.Row="1" >
            <TextBlock x:Name="lbCompanyName" Text="Company Name" FontSize="36" ></TextBlock>
            <TextBox x:Name="txtCompanyName" Text="{Binding CompanyName,Mode=TwoWay}" Height="80" FontSize="36"/>
            <TextBlock x:Name="lbContactName" Text="Contact Name" FontSize="36"></TextBlock>
            <TextBox x:Name="txtContactName" Text="{Binding ContactName,Mode=TwoWay}"  Height="80"  FontSize="36"/>
            <TextBlock x:Name="lbPhone" Text="Phone"  FontSize="36"></TextBlock>
            <TextBox x:Name="txtPhone" Text="{Binding Phone,Mode=TwoWay}"  Height="80" FontSize="36" />
            <Button Content="Submit" Height="71" Name="button1" Width="160" Click="button1_Click" />
        </StackPanel>
    </Grid>
 
</phone:PhoneApplicationPage>
 
然後修改DetailPage.xaml.cs
 
DetailPage.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 System.Windows.Navigation;
using Microsoft.Phone.Controls;
using System.Reflection;
 
namespace WindowsPhoneListApplication1
{
    public partial class DetailsPage : PhoneApplicationPage
    {
        private ServiceReference1.ChangeSetEntry _entery = null;
 
        // Constructor
        public DetailsPage()
        {
            InitializeComponent();
        }
 
        private void BuildOriginalEntity(ServiceReference1.Customers original)
        {
            _entery = new ServiceReference1.ChangeSetEntry();
            ServiceReference1.Customers c = new ServiceReference1.Customers();
            foreach (var prop in c.GetType().GetProperties())
                prop.SetValue(c, prop.GetValue(original, null), null);
            _entery.OriginalEntity = c;
        }
 
        // When page is navigated to, set data context to selected item in list
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
 
            string selectedIndex = "";
            if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
            {
                int index = int.Parse(selectedIndex);
                DataContext = App.ViewModel.Items[index];
                BuildOriginalEntity(App.ViewModel.Items[index]);
            }
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            _entery.Entity = DataContext;
            _entery.Operation = ServiceReference1.DomainOperation.Update;
            App.ViewModel._client.SubmitChangesCompleted += new EventHandler<ServiceReference1.SubmitChangesCompletedEventArgs>(_client_SubmitChangesCompleted);
            App.ViewModel._client.SubmitChangesAsync(
                new System.Collections.ObjectModel.ObservableCollection<ServiceReference1.ChangeSetEntry>(){
                    _entery
                });
        }
 
        void _client_SubmitChangesCompleted(object sender, ServiceReference1.SubmitChangesCompletedEventArgs e)
        {
            if (e.Error == null)
                MessageBox.Show("Updated");
            App.ViewModel._client.SubmitChangesCompleted -= new EventHandler<ServiceReference1.SubmitChangesCompletedEventArgs>(_client_SubmitChangesCompleted);
        }
    }
}
 
不可諱言,現在的RIA ServcieWindows Phone 7 SDK中支援並不完善,所以我們得繞著路走,要呼叫SubmitChanges函式,必須提供
一群ChangeSetEntry,每個ChangeSetEntry代表著一筆資料列的異動,其必須包含原始資料物件及更新資料物件,因此在DetailPage一開始時,
即將原始資料列以Reflection方式保存下來,待使用者按下Submit按紐後,再指定更新後的資料物件給ChangeSetEntry,並透過SubmitChanges來更新,
22是執行畫面。
 
22
 
 
 
 
Consuming WCF RIA Service – OData Version
 
 
       OData(Open Data Protocol)Microsoft近日來主推的開放資料存取協定,RIA ServiceWindows Phone 7也提供了初步的支援,要在Windows Phone 7
中使用OData,得先下載OData for Windows Phone 7Library
下載後解壓至某個目錄後,然後將原本專案中的NorthwindSvc.csNorthwindSvc.metadata.cs刪除,再重新建立Domain Service,此次請選擇expose OData endpoint 
23
 
編譯後,請於Phone List Application專案中加入OData Client SDK的參考。
 
24
 
一切無誤的話,應該可透過IE看到RIA ServiceexposeOData資料。
 
25
 
重點來了,目前的Windows Phone 7 SDK無法於Visual Studio 2010中直接取用RIA ServiceOData資訊,所以得回到命令列來做。
 
datasvcutil /uri:http://localhost:15415/W
ebApplication1-NorthwindSvc.svc/odata/ /out:Reference1.cs /Version:2.0 /DataServ
iceCollection
26
 
接著刪除Phone List Application中的ServiceReference1,再加入由DataSvcutil產生的Reference1.cs,修改MainViewModel中的程式碼。
 
MainViewModel.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Linq;
using System.Data.Services.Client;
using System.Data.Services.Common;
 
namespace WindowsPhoneListApplication1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        internal WebApplication1.NorthwindSvc _client = null;
 
        public MainViewModel()
        {
            Items = new ObservableCollection<WebApplication1.Customers>(); // default.
            _client = new WebApplication1.NorthwindSvc(new Uri("http://localhost:15415/WebApplication1-NorthwindSvc.svc/OData/"));
            var query = from s1 in _client.CustomersSet select s1;
            var dsQuery = (DataServiceQuery<WebApplication1.Customers>)query;
            dsQuery.BeginExecute(ar =>
            {
                var results = dsQuery.EndExecute(ar).ToList();
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    foreach (var item in results)
                        Items.Add(item);
                });
            }, null);
        }
 
        public ObservableCollection<WebApplication1.Customers> Items { get; private set; }
 
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
由於目前的OData for Windows Phone 7尚未支援資料的修改,所以請修改DetailPage,將Submit按紐拿掉,並拿掉
DetailsPage.xaml.cs有關更新的程式碼。
 
DetailsPage.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 System.Windows.Navigation;
using Microsoft.Phone.Controls;
using System.Reflection;
 
namespace WindowsPhoneListApplication1
{
    public partial class DetailsPage : PhoneApplicationPage
    {
        // Constructor
        public DetailsPage()
        {
            InitializeComponent();
        }
        // When page is navigated to, set data context to selected item in list
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
 
            string selectedIndex = "";
            if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
            {
                int index = int.Parse(selectedIndex);
                DataContext = App.ViewModel.Items[index];
            }
        }
    }
}
27
 
 
 
後記
 
     Windows Phone 7對於RIA Service的支援,目前雖然尚未完善,但有著Silverlight 4的經驗,相信很快的我們就能在Windows Phone 7上
開發商業型的資料庫應用程式,這將可滿足一部份想使用Windows Phone 7做為行動商業裝置的用戶。
 
註1:目前的Windows Phone 7 模擬器並無法執行於VM中,例如Virtual PC/VMWare,所以不要嘗試裝在裡面。