稳扎稳打Silverlight(56) - 4.0通信之与 WCF Data Services 进行通信

[索引页]
[源码下载]


稳扎稳打Silverlight(56) - 4.0通信之与 WCF Data Services 进行通信



作者:webabcd


介绍
Silverlight 4.0 对 WCF Data Services 的支持:

  • DataServiceCollection<T> - 继承自 ObservableCollection<T>,用于将 WCF Data Services 提供的数据绑定到 Silverlight 控件上,当数据发生变化时可提供通知



在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


示例
演示 Silverlight 4.0 与 WCF Data Services 之间的通信
1、服务端
MyWCFDataService.svc.cs

代码
/*
 * WCF Data Services - 用于提供基于 OData 协议的数据服务
 * OData 协议 - 开放数据协议(Open Data Protocol),其基于 REST-ful 协议,参考:
http://www.odata.org/
 
*/

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace Silverlight40.Web.Service
{
    
public class MyWCFDataService : DataService<Model.NorthwindEntities>
    {
        
public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule(
"*", EntitySetRights.All);

            
// 指定对 Products, Categories, Orders 启用服务端分页,页大小为 3
            config.SetEntitySetPageSize("Products"3);
            config.SetEntitySetPageSize(
"Categories"3);
            config.SetEntitySetPageSize(
"Orders"3);

            config.DataServiceBehavior.MaxProtocolVersion 
= DataServiceProtocolVersion.V2;
        }
    }
}



2、客户端
Demo.xaml

代码
<navigation:Page x:Class="Silverlight40.WCFDataServices.Demo" 
           xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           xmlns:sdk
="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
           Title
="Demo Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel Orientation="Vertical" HorizontalAlignment="Left">

            
<!--
                    用于演示通过 WCF Data Services 实现数据的增删改查
                
-->
            
<StackPanel Orientation="Horizontal">
                
<Button Name="btnGetData" Content="获取数据" Margin="5" Click="btnGetData_Click" />
            
</StackPanel>

            
<TextBlock Text="产品类别列表:" Margin="5" />
            
<sdk:DataGrid Name="gridCategory" Margin="5" Height="200" Width="400" AutoGenerateColumns="False" ItemsSource="{Binding}" 
                       SelectionChanged
="gridCategory_SelectionChanged">
                
<sdk:DataGrid.Columns>
                    
<sdk:DataGridTextColumn Header="类别ID" Binding="{Binding CategoryID}" IsReadOnly="True" />
                    
<sdk:DataGridTextColumn Header="类别名称" Binding="{Binding CategoryName}" />
                
</sdk:DataGrid.Columns>
            
</sdk:DataGrid>

            
<TextBlock Text="产品列表:" Margin="5" />
            
<sdk:DataGrid Name="gridProduct" Margin="5" Height="200" Width="400" AutoGenerateColumns="False" ItemsSource="{Binding}" >
                
<sdk:DataGrid.Columns>
                    
<sdk:DataGridTextColumn Header="产品ID" Binding="{Binding ProductID}" IsReadOnly="True" />
                    
<sdk:DataGridTextColumn Header="产品名称" Binding="{Binding ProductName}" />
                    
<sdk:DataGridTextColumn Header="单价" Binding="{Binding UnitPrice}" IsReadOnly="True" />
                
</sdk:DataGrid.Columns>
            
</sdk:DataGrid>

            
<Button Name="btnSave" Content="保存" Margin="5" Width="400" Click="btnSave_Click" />



            
<!--
                    用于演示 WCF Data Services 的服务端分页
                
-->
            
<TextBlock Text="订单列表:" Margin="5,20,5,5" />
            
<sdk:DataGrid Name="gridOrder" Margin="5" Height="200" Width="400" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding}" >
                
<sdk:DataGrid.Columns>
                    
<sdk:DataGridTextColumn Header="订单ID" Binding="{Binding OrderID}" />
                    
<sdk:DataGridTextColumn Header="客户ID" Binding="{Binding CustomerID}" />
                
</sdk:DataGrid.Columns>
            
</sdk:DataGrid>
            
<TextBlock Name="txtCurrentPageIndex" />
            
<Button Name="btnPrev" Content="上一页" Margin="5" Width="400" />
            
<Button Name="btnNext" Content="下一页" Margin="5" Width="400" />

        
</StackPanel>
    
</Grid>
</navigation:Page>


Demo.xaml.cs

代码
/*
 * 演示 Silverlight 4.0 与 WCF Data Services 之间的通信
 * 
 * DataServiceCollection<T> - 继承自 ObservableCollection<T>。用于将 WCF Data Services 提供的数据绑定到 Silverlight 控件上,当数据发生变化时可提供通知
 *     LoadAsync(IQueryable<T>) - 从数据服务上异步加载 IQueryable<T> 数据到 DataServiceCollection<T> 中(在 LoadCompleted 触发之前不能再调用此方法)
 *     LoadAsync() - 当 DataServiceCollection<T> 表示为某实体的导航属性时,从数据服务上异步加载该数据(在 LoadCompleted 触发之前不能再调用此方法)
 *     LoadCompleted - 异步加载完成后所触发的事件
 *         LoadCompletedEventArgs - LoadCompleted 事件的事件参数
 *         LoadCompletedEventArgs.QueryOperationResponse - 获取数据服务对改查询操作的响应
 *             QueryOperationResponse.Error - 引发的异常
 *             QueryOperationResponse.Headers -  HTTP 的响应头
 *             QueryOperationResponse.Query - 对应的 DataServiceQuery(DataServiceQuery.RequestUri - 请求数据服务的 URI) 对象
 *             QueryOperationResponse.StatusCode - HTTP 的响应代码
 *     Continuation - 返回一个 DataServiceQueryContinuation<T> 对象,该对象封装了当前查询结果的下一页的 URI
 *         DataServiceQueryContinuation<T>.NextLinkUri - 当前查询结果的下一页的 URI
 *     LoadNextPartialSetAsync() - 加载下一页数据到 DataServiceCollection<T> 中
 * 
 * Silverlight 通过 ObservableCollection<T> 与 ADO.NET Data Services 1.0 进行通信详见 
http://www.cnblogs.com/webabcd/archive/2009/03/12/1409281.html
 * WCF Data Services(ADO.NET Data Services 1.5)新特性详见 
http://www.cnblogs.com/webabcd/archive/2010/06/11/1756071.html
 
*/

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 Silverlight40.MyWCFDataServiceReference;
using System.Data.Services.Client;

namespace Silverlight40.WCFDataServices
{
    
public partial class Demo : Page
    {
        
private NorthwindEntities _context;
        
private DataServiceCollection<Category> _categories;

        
public Demo()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
// 指定数据服务地址
            _context = new NorthwindEntities(new Uri("Service/MyWCFDataService.svc", UriKind.Relative));

            _categories 
= new DataServiceCollection<Category>();
            _categories.LoadCompleted 
+= new EventHandler<LoadCompletedEventArgs>(_categories_LoadCompleted);

            
// 演示如何通过 WCF Data Services 做服务端分页
            ServerPagingDemo();
        }

        
// 开始异步加载 Categories 数据
        private void btnGetData_Click(object sender, RoutedEventArgs e)
        {
            gridCategory.DataContext 
= null;
            gridProduct.DataContext 
= null;

            
// 加载 Categories 表中的全部数据
            var query = from c in _context.Categories select c;
            _categories.LoadAsync(query);

            btnGetData.IsEnabled 
= false;
        }

        
// 异步加载 Categories 数据完成
        void _categories_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            
if (e.Error == null)
            {
                
if (_categories.Continuation != null)
                {
                    
// 在数据服务中 Categories 被服务端分页了,所以需要不断调用 LoadNextPartialSetAsync() ,以便加载全部的 Categories 数据
                    _categories.LoadNextPartialSetAsync();
                }
                
else
                {
                    gridCategory.DataContext 
= _categories;
                    gridCategory.SelectedIndex 
= 0;

                    btnGetData.IsEnabled 
= true;
                }
            }
            
else
            {
                MessageBox.Show(e.Error.ToString());
                btnGetData.IsEnabled 
= true;
            }
        }

        
// 开始异步加载指定 Category 下的 Products 数据
        private void gridCategory_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Category category 
= gridCategory.SelectedItem as Category;

            
if (category != null)
            {
                
if (category.Products.Count == 0)
                {
                    category.Products.LoadCompleted 
+= new EventHandler<LoadCompletedEventArgs>(Products_LoadCompleted);

                    
try
                    {
                        
// 加载实体的导航属性数据
                        category.Products.LoadAsync();
                    }
                    
catch (InvalidOperationException ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
                
else
                {
                    gridProduct.DataContext 
= category.Products;
                }
            }
        }

        
// 异步加载 Products 数据完成
        void Products_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            
if (e.Error == null)
            {
                DataServiceCollection
<Product> products = sender as DataServiceCollection<Product>;

                
if (products.Continuation != null)
                {
                    
try
                    {
                        products.LoadNextPartialSetAsync();
                    }
                    
catch (InvalidOperationException ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
                
else
                {
                    gridProduct.DataContext 
= products;
                }
            }
            
else
            {
                MessageBox.Show(e.Error.ToString());
            }
        }

        
// 异步保存 Categories 中的被更新的数据(包括增删改),由于 Products 是 Category 的导航属性,所以相关的 Products 的数据的更新也会被保存
        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            
try
            {
                
/*
                 * NorthwindEntities - 继承自 DataServiceContext,在 VS 中引用服务后会自动生成这个对象
                 *     DataServiceContext.BeginSaveChanges() - 将有变化的数据提交至数据服务端进行更新
                 *     DataServiceContext.EndSaveChanges() - 获取 BeginSaveChanges() 操作的结果,返回一个 DataServiceResponse 类型的对象
                 
*/

                _context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, 
null);
            }
            
catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        
// 数据被异步保存后
        private void OnChangesSaved(IAsyncResult result)
        {
            
bool error = false;

            
this.Dispatcher.BeginInvoke(() =>
            {
                
try
                {
                    DataServiceResponse response 
= _context.EndSaveChanges(result);

                    
foreach (ChangeOperationResponse changeResponse in response)
                    {
                        
if (changeResponse.Error != null)
                            error 
= true;
                    }

                    
if (!error)
                    {
                        MessageBox.Show(
"数据更新成功");
                    }
                    
else
                    {
                        MessageBox.Show(
"数据更新失败");
                    }
                }
                
catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            });
        }



        
private int _pageIndex = 0;
        
private int _pageSize = 3;

        
// 演示如何通过 WCF Data Services 做服务端分页
        private void ServerPagingDemo()
        {
            BindOrder();

            btnNext.Click 
+= (s, args) =>
            {
                _pageIndex
++;
                BindOrder();
            };

            btnPrev.Click 
+= (s, args) =>
            {
                _pageIndex
--;
                BindOrder();
            };
        }

        
private void BindOrder()
        {
            txtCurrentPageIndex.Text 
= "当前页索引:" + _pageIndex.ToString();

            var query 
= from o in _context.Orders select o;
            query 
= query.Skip(_pageIndex * _pageSize).Take(_pageSize);
            DataServiceCollection
<Order> orders = new DataServiceCollection<Order>();
            orders.LoadAsync(query);

            orders.LoadCompleted 
+= (s, args) =>
            {
                gridOrder.DataContext 
= orders;
            };
        }
    }
}



OK
[源码下载]

posted @ 2010-10-11 08:06  webabcd  阅读(5894)  评论(6编辑  收藏  举报