zoukankan      html  css  js  c++  java
  • 与众不同 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(10, 99);
                product.UnitPrice = 6.66m;
                product.Discontinued = false;
    
                var vm = App.Current.Resources["ODataViewModel"] as MyViewModel;
                vm.AddProduct(product);
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    项目经理必备的8个要素:沟通、总结、懂技术
    完工概率计算总结
    PMP--可能会涉及到的计算题
    六顶思考帽子法
    预测技术
    React.Component与React.PureComponent的区别
    简单理解JavaScript,TypeScript和JSX
    自己常用的linux命令
    ES6 promise 用法
    node的express框架接收get/post请求时,参数获取方式
  • 原文地址:https://www.cnblogs.com/webabcd/p/2678196.html
Copyright © 2011-2022 走看看