与众不同 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 ...
随机推荐
- 【CSDN博客之星评选】我为什么坚持写博客
今天无意中在CSDN的博客之星评选活动看到自己竟然是候选人之一,真的是十分的惊讶也十分的高兴.对于喜欢写东西.喜欢分享的我来说,已经忍不住用文字来记录一下今天的美好心情,同时也让我回想起我是如何开始在 ...
- 高级UIKit-04(NSUserDefaults、NSKeyedArchiver、对象归档方法)
[day05_1_UserDefault]:判断应用程序是否是第一次运行 NSUserDefaults:用来保存应用程序的配置信息如:程序运行次数,用户登陆信息等. // 使用系统提供的NSUserD ...
- jquery插件讲解:轮播(SlidesJs)+验证(Validation)
SlidesJs(轮播支持触屏)——官网(http://slidesjs.com) 1.简介 SlidesJs是基于Jquery(1.7.1+)的响应幻灯片插件.支持键盘,触摸,css3转换. 2.代 ...
- Cubieboard4卡片式电脑
Cubieboard4 also named CC-A80, is a open source mini PC or single board computer which has ultra-pow ...
- asp.net后台对前台脚本的调用
后台像前台输出要执行的脚本 Response.Write("<script>alert('内容')</script>"); asp.net后台调用前台js脚 ...
- BZOJ 1529: [POI2005]ska Piggy banks( 并查集 )
每一连通块砸开一个就可以拿到所有的钱, 所以用并查集求连通块数 ------------------------------------------------------------------- ...
- wkhtmltopdf 生成pdf
public class PdfHelper { static string RootPath { get { string AppPath = ""; HttpContext H ...
- 获取wpf datagrid当前被编辑单元格的内容
原文 获取wpf datagrid当前被编辑单元格的内容 确认修改单元个的值, 使用到datagrid的两个事件 开始编辑事件 BeginningEdit="dataGrid_Beginni ...
- 基于visual Studio2013解决面试题之1409基数排序
题目
- Python文件处理(1)
读取文件 解决方案: 最简单的就是一次性读取所有的内容放在一个大字符串中 all_the_text=open('thefile.txt').read() all_the_data=open('abin ...