与众不同 windows phone (29) - Communication(通信)之与 OData 服务通信
原文:与众不同 windows phone (29) - Communication(通信)之与 OData 服务通信
作者:webabcd
介绍
与众不同 windows phone 7.5 (sdk 7.1) 之通信
- 与 OData 服务通信
示例
1、服务端(采用 Northwind 示例数据库)
NorthwindService.svc.cs
/*
* 提供 OData 服务,详细说明请参见 WCF Data Services 的相关文章:http://www.cnblogs.com/webabcd/category/181636.html
*/ 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 Web.Communication
{
// 出现异常时,返回详细的错误信息
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class NorthwindService : DataService<NorthwindEntities>
{
public static void InitializeService(DataServiceConfiguration config)
{
// 全部实体全部权限
config.SetEntitySetAccessRule("*", EntitySetRights.All);
// 指定服务所支持的 OData 协议的最大版本
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
2、客户端(ViewModel 层)
MyViewModel.cs
/*
* 调用 OData 服务的 ViewModel 层
*
* DataServiceCollection<T> - OData 服务的实体数据集合,添加、删除和更新数据时都会提供通知,继承自 ObservableCollection<T>
* Count - 实体数据集合中的实体数
* CollectionChangedCallback - 实体集合更改时调用的委托
* EntityChangedCallback - 实体更改时调用的委托
* Continuation - 是否还有下一页数据
* LoadAsync(IQueryable<T> query) - 通过指定的查询异步加载数据
* CancelAsyncLoad() - 取消异步加载请求
* LoadNextPartialSetAsync() - 加载下一页数据
* Detach() - 停止跟踪集合中的全部实体
* LoadCompleted - 异步数据加载完成后触发的事件
*
*
* DataServiceState - 服务状态
* Serialize(DataServiceContext context, Dictionary<string, Object> collections) - 序列化 DataServiceContext 对象以及页面的相关数据
* 注:引用 OData 服务后,会自动生成一个继承自 DataServiceContext 的代理类,如果需要序列化的话,则必须手动为其加上 [System.Runtime.Serialization.DataContract]
* Deserialize() - 反序列化,返回 DataServiceState 类型的数据
* Context - 相关的 DataServiceContext 对象
* RootCollections - 相关的数据
*
*
* 注:
* OData 服务的相关查询参数参见:http://msdn.microsoft.com/en-us/library/gg309461.aspx
*/ using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes; using System.ComponentModel;
using Demo.NorthwindContext;
using System.Data.Services.Client;
using System.Linq;
using System.Collections.Generic; namespace Demo.Communication.ODataClient.ViewModel
{
public class MyViewModel : INotifyPropertyChanged
{
// 引用过来的 OData 服务
private NorthwindEntities _context;
// OData 服务地址
private Uri _northwindUri = new Uri("http://localhost:15482/Communication/NorthwindService.svc/"); // 相关数据,DataServiceCollection<T> 继承自 ObservableCollection<T>
public DataServiceCollection<Category> Categories { get; private set; } public void LoadData()
{
_context = new NorthwindEntities(_northwindUri); // 实例化 DataServiceCollection<Category>,并注册相关事件
Categories = new DataServiceCollection<Category>(_context);
Categories.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(Categories_LoadCompleted); // 获取全部 Categories 数据,并且一次请求带上 Categories 的所有 Products
DataServiceQuery<Category> query = _context.Categories.Expand("Products");
Categories.LoadAsync(query); NotifyPropertyChanged("Categories");
} void Categories_LoadCompleted(object sender, LoadCompletedEventArgs e)
{
if (e.Error == null)
{
// 如果服务端有分页,则继续获取直至获取完全部数据
if (Categories.Continuation != null)
Categories.LoadNextPartialSetAsync();
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
MessageBox.Show(e.Error.ToString());
});
}
} // 新增产品数据
public void AddProduct(Product product)
{
_context.AddToProducts(product); Categories.Single(p => p.CategoryID == product.CategoryID).Products.Add(product); SaveChanges();
} // 删除产品数据
public void DeleteProduct(Product product)
{
_context.DeleteObject(product); Categories.Single(p => p.CategoryID == product.CategoryID).Products.Remove(product); SaveChanges();
} // 更新产品数据
public void UpdateProduct(Product product)
{
_context.UpdateObject(product); SaveChanges();
} public void SaveChanges()
{
// 异步向 OData 服务提交最近的数据变化
_context.BeginSaveChanges(OnChangesSaved, _context);
} private void OnChangesSaved(IAsyncResult result)
{
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
_context = result.AsyncState as NorthwindEntities; try
{
// 完成数据提交
_context.EndSaveChanges(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
});
} // 一个异步获取数据的例子,此 Demo 没用到此方法
public void GetData()
{
// 查找 Products 里 ProductID 为 1 的数据
var query = _context.CreateQuery<Product>("Products").AddQueryOption("$filter", "ProductID eq 1"); // 异步请求 OData 服务
query.BeginExecute(p =>
{
var myQuery = p.AsyncState as DataServiceQuery<Product>; try
{
// 获取请求结果
var result = myQuery.EndExecute(p).First();
// 更新数据
_context.UpdateObject(result);
// 将更新后的结果提交到 OData 服务
SaveChanges();
}
catch (Exception ex)
{
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
MessageBox.Show(ex.ToString());
});
}
}, query);
} // 序列化当前数据,Deactivated 保存此值到应用程序状态,参见 App.xaml.cs
public string GetState()
{
var dict = new Dictionary<string, object>();
dict["categories"] = Categories; return DataServiceState.Serialize(_context, dict);
} // 恢复数据,当从 tombstone 状态进入 Activated 时,则从应用程序状态中恢复数据,参见 App.xaml.cs
public void RestoreState(string appState)
{
Dictionary<string, object> dict; if (!string.IsNullOrEmpty(appState))
{
DataServiceState state = DataServiceState.Deserialize(appState); // 获取相关数据
var context = state.Context as NorthwindEntities;
dict = state.RootCollections;
DataServiceCollection<Category> categories = dict["Categories"] as DataServiceCollection<Category>; // 恢复相关数据
_context = context;
Categories = categories;
Categories.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(Categories_LoadCompleted);
NotifyPropertyChanged("Categories");
}
} public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
3、客户端(View 层)
App.xaml
<Application
x:Class="Demo.App"
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:odataViewModel="clr-namespace:Demo.Communication.ODataClient.ViewModel"> <Application.Resources> <odataViewModel:MyViewModel x:Key="ODataViewModel" /> </Application.Resources> </Application>
App.xaml.cs
private void Application_Activated(object sender, ActivatedEventArgs e)
{
// 从 tombstone 状态返回,则恢复相关数据,参见:“调用 OData 服务”
if (!e.IsApplicationInstancePreserved)
{
if (PhoneApplicationService.Current.State.ContainsKey("categoriesState"))
{
var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
string categoriesState = PhoneApplicationService.Current.State["categoriesState"] as string; vm.RestoreState(categoriesState);
}
}
} private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
// 保存相关数据,参见:“调用 OData 服务”
var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
PhoneApplicationService.Current.State["categoriesState"] = vm.GetState();
}
Demo.xaml
<phone:PhoneApplicationPage
x:Class="Demo.Communication.ODataClient.Demo"
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" DataContext="{Binding Source={StaticResource ODataViewModel}}"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"> <phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="item">
<ListBox ItemsSource="{Binding Products}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="460" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions> <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{Binding ProductName}" />
<TextBlock Text="{Binding UnitPrice}" Margin="10 0 0 0" />
</StackPanel> <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
<Button x:Name="btnUpdate" Content="更新" Click="btnUpdate_Click" />
<Button x:Name="btnDelete" Content="删除" Click="btnDelete_Click" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
<DataTemplate x:Key="header">
<TextBlock Text="{Binding CategoryName}" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources> <Grid x:Name="LayoutRoot" Background="Transparent">
<controls:Pivot x:Name="pivot"
Title="产品列表"
ItemTemplate="{StaticResource item}"
HeaderTemplate="{StaticResource header}"
ItemsSource="{Binding Categories}">
</controls:Pivot>
</Grid> <phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar Mode="Default" IsVisible="True">
<shell:ApplicationBarIconButton x:Name="btnAd" IconUri="/ApplicationBarDemo/Assets/appbar.add.rest.png" Text="添加" Click="btnAd_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar> </phone:PhoneApplicationPage>
Demo.xaml.cs
/*
* 调用 OData 服务的 View 层
*/ 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 Demo.Communication.ODataClient.ViewModel;
using Demo.NorthwindContext; namespace Demo.Communication.ODataClient
{
public partial class Demo : PhoneApplicationPage
{
public Demo()
{
InitializeComponent(); this.Loaded += new RoutedEventHandler(Demo_Loaded);
} void Demo_Loaded(object sender, RoutedEventArgs e)
{
// 加载数据
var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
vm.LoadData();
} private void btnDelete_Click(object sender, RoutedEventArgs e)
{
var product = (sender as Button).DataContext as Product; // 删除指定的产品数据
var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
vm.DeleteProduct(product);
} private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
// 更新指定的产品数据
var product = (sender as Button).DataContext as Product;
product.UnitPrice = 8.88m; var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
vm.UpdateProduct(product);
} private void btnAd_Click(object sender, EventArgs e)
{
// 在指定的类别下添加一个新的产品数据
var category = pivot.SelectedItem as Category; Product product = new Product();
product.CategoryID = category.CategoryID;
product.ProductName = "测试" + new Random().Next(, );
product.UnitPrice = 6.66m;
product.Discontinued = false; var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
vm.AddProduct(product);
}
}
}
OK
[源码下载]
与众不同 windows phone (29) - Communication(通信)之与 OData 服务通信的更多相关文章
- 与众不同 windows phone (33) - Communication(通信)之源特定组播 SSM(Source Specific Multicast)
原文:与众不同 windows phone (33) - Communication(通信)之源特定组播 SSM(Source Specific Multicast) [索引页][源码下载] 与众不同 ...
- 与众不同 windows phone (32) - Communication(通信)之任意源组播 ASM(Any Source Multicast)
原文:与众不同 windows phone (32) - Communication(通信)之任意源组播 ASM(Any Source Multicast) [索引页][源码下载] 与众不同 wind ...
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- RRiBbit,一个事件总线.基于spring配置不同服务通信!
1.何为RRiBbit? *一种开源事件总线技术,能够让模块(组件)之间双向通讯,也被称为请求相应总线(request-response-bus),使用简单,相对其他框架来说,RRiBbit只需要加个 ...
- 与众不同 windows phone (46) - 8.0 通信: Socket, 其它
[源码下载] 与众不同 windows phone (46) - 8.0 通信: Socket, 其它 作者:webabcd 介绍与众不同 windows phone 8.0 之 通信 Socket ...
- 与众不同 windows phone 8.0 & 8.1 系列文章索引
[源码下载] [与众不同 windows phone 7.5 (sdk 7.1) 系列文章索引] 与众不同 windows phone 8.0 & 8.1 系列文章索引 作者:webabcd ...
- 与众不同 windows phone (39) - 8.0 联系人和日历
[源码下载] 与众不同 windows phone (39) - 8.0 联系人和日历 作者:webabcd 介绍与众不同 windows phone 8.0 之 联系人和日历 自定义联系人存储的增删 ...
- 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox
[源码下载] 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox 作者:webabcd ...
随机推荐
- 从 Qt 的 delete 说开来
原地址:http://blog.csdn.net/dbzhang800/article/details/6300025 在C++中学习过程中,我们都知道: delete 和 new 必须 配对使用(一 ...
- SQL2005、2008、2000 清空删除日志
SQL2005清空删除日志: 代码如下: Backup Log DNName with no_log '这里的DNName是你要收缩的数据库名,自己注意修改下面的数据库名,我就不再注释了. go d ...
- 《高质量程序设计指南:C++/C语言》面试题整理
本试题仅用于考查C++/C程序员的基本编程技能.内容限于C++/C常用 语法,不涉及 数据结构. 算法以及深奥的语法.考试成绩能反映出考生的编程质量以及对C++/C的理解程度,但不能反映考生的智力和软 ...
- Codeforces Beta Round #10 B. Cinema Cashier (树状数组)
题目大意: n波人去k*k的电影院看电影. 要尽量往中间坐,往前坐. 直接枚举,贪心,能坐就坐,坐在离中心近期的地方. #include <cstdio> #include <ios ...
- 基于JSP+SERVLET的新闻发布系统(一)
本系统使用的是基于JSP+SERVLET+TOMCAT6 数据库使用的是MYSQL IDE是MYECLIPSE8.5,页面编辑使用的是百度的ueditor,比较适合咱国人 采用MVC模式,使用的关键技 ...
- 使用tmux [FreeBSDChina Wiki]
使用tmux [FreeBSDChina Wiki] 使用tmux tmux是一个优秀的终端复用软件,类似GNU Screen,但来自于OpenBSD,采用BSD授权.使用它最直观的好处就是,通过一个 ...
- [Java][activiti]Activiti这个过程委托功能[getAssignee()与getOwner()差异]
一.流程图: 二.流程定义文件: AssigneeUserAndGroup.bpmn 三.单元測试: ProcessTestDelegateTask.java 四.主要运行语句 // 签收 taskS ...
- 1352 - Colored Cubes (枚举方法)
There are several colored cubes. All of them are of the same size but they may be colored differentl ...
- Storm流计算从入门到精通之技术篇(高并发策略、批处理事务、Trident精解、运维监控、企业场景)
1.Storm全面.系统.深入讲解,采用最新的稳定版本Storm 0.9.0.1 : 2.注重实践,对较抽象难懂的技术点如Grouping策略.并发度及线程安全.批处理事务.DRPC.Storm ...
- Leetcode:find_minimum_in_rotated_sorted_array
一. 题目 给定一个排好序的数组.数组可能是单调递增,也可能有一个变换. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2) 要求找出最小的数. ...