反应性扩展框架(Reactive Extensions)

转载 2012年03月22日 21:48:59

    Reactive 编程模型:Reactive Extensions for .NET Framework 是一个托管库,它提供用于编写反应式应用程序的 API。反应式应用程序是由其环境驱动的。在反应式模型中,数据流、异步请求以及事件都表示为可观察序列。应用程序可以订阅这些可观察序列,以在新数据到达时接收异步消息。Reactive Extensions 允许应用程序使用查询运算符组合这些序列。如果您的应用程序与多个数据源(如用户输入事件、Web 服务请求以及系统通知)交互,则管理所有这些交互的便利方法是为每个数据流实现单独的处理程序。在这些处理程序中,您必须提供代码以在所有不同的数据流之间进行协调并将该数据处理为可使用的形式。Reactive Extensions 允许您编写一个查询,该查询将所有这些数据流组合成触发单个处理程序的单个流。筛选、同步和转换数据等工作由 Reactive Extensions 查询执行,以便您的处理程序只需对接收的数据进行反应并对该数据进行某些处理。

      下面是林永坚对反应性扩展框架的总结:

    在前一篇博文中,学习了如何使用地理位置服务(Location Service),但是在模拟器上我们无法获得相关的地理位置信息,下面用这节学习的内容模拟地理位置的数据~

MainPage.xaml代码如下:

View Code
<phone:PhoneApplicationPage 
x:Class="RecativeExtension.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"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">

<!--LayoutRoot is the root grid where all 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="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="示例程序" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="反应性扩展框架" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>

<!--ContentPanel - place additional content here-->

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Height="30" HorizontalAlignment="Left" Margin="27,76,0,0" Name="textBlock1" Text="经度" VerticalAlignment="Top" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="24,153,0,0" Name="textBlock2" Text="纬度" VerticalAlignment="Top" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="70,50,0,0" Name="logTxtBox" Text="" VerticalAlignment="Top" Width="460" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="70,128,0,0" Name="latTxtBox" Text="" VerticalAlignment="Top" Width="460" />
<Button Content="开始" Height="72" HorizontalAlignment="Left" Margin="70,299,0,0" Name="button1" VerticalAlignment="Top" Width="160" Click="button1_Click" />
<Button Content="结束" Height="72" HorizontalAlignment="Left" Margin="248,299,0,0" Name="button2" VerticalAlignment="Top" Width="160" Click="button2_Click" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="24,230,0,0" Name="textBlock3" Text="状态" VerticalAlignment="Top" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="70,206,0,0" Name="statusTxtBox" Text="" VerticalAlignment="Top" Width="460" />

</Grid>
</Grid>

<!--Sample code showing usage of ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

MainPage.xaml.cs代码如下:

View Code
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 System.Device.Location;
using Microsoft.Phone.Reactive;
using System.Threading;

namespace RecativeExtension
{
public partial class MainPage : PhoneApplicationPage
{
GeoCoordinateWatcher watcher;
bool useEmulation = true;
// Constructor
public MainPage()
{
InitializeComponent();
}

private void StartEmulation()
{
// EmulatePositionChangedEvents returns an IEnumerable object.
// Convert this to an Observable sequence.
var position = EmulatePositionChangedEvents().ToObservable();

// Subscribe to the Observable sequence.
// Use null for the sender parameter to the event handler.
position.Subscribe(evt => watcher_PositionChanged(null, evt));
}

static IEnumerable<GeoPositionChangedEventArgs<GeoCoordinate>> EmulatePositionChangedEvents()
{
// Create a Random object to create random numbers.
Random random = new Random();

// Loop infinitely.
for (; ; )
{
// Pause for 100 milliseconds in each loop.
Thread.Sleep(random.Next(100));

// Generate a random latitude and longitude. You could also load position data from a file or
// generate the data from user input.
double latitude = (random.NextDouble() * 180.0) - 90.0; // latitude is between -90 and 90
double longitude = (random.NextDouble() * 360.0) - 180.0; // longitude is between -180 and 180

// Use yield to return a new instance of the GeoPositionChangedEventArgs class that is exposed
// through the IEnumerable interface.
yield return new GeoPositionChangedEventArgs<GeoCoordinate>(
new GeoPosition<GeoCoordinate>(DateTimeOffset.Now, new GeoCoordinate(latitude, longitude)));

}
}

// Event handler for location data. This invokes code on the
// page's main thread.
private void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
Dispatcher.BeginInvoke(() =>
{
latTxtBox.Text = e.Position.Location.Latitude.ToString("0.00");
logTxtBox.Text = e.Position.Location.Longitude.ToString("0.00");
});
}

private void button1_Click(object sender, RoutedEventArgs e)
{
// First, handle the case where emulation is not being used.
if (!useEmulation)
{
// Initialize the GeoCoordinateWatcher.
watcher = new GeoCoordinateWatcher();

// Reactive Extensions uses Observable sequences to represent data streams.
// Create an Observable sequence from the event stream using the FromEvent method.
// This method uses the .NET Generic syntax to specify the type of event args for the event.
// The parameters to the method are the add and remove handlers of the GeoCoordinateWatcher object.
IObservable<IEvent<GeoPositionChangedEventArgs<GeoCoordinate>>> positionEventAsObservable =
Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(
ev => watcher.PositionChanged += ev,
ev => watcher.PositionChanged -= ev);

// Subscribe to the observable data stream. You can use the same event handler as if you
// were using the GeoCoordinateWatcher.PositionChanged event directly.
var positionSubscription = positionEventAsObservable.Subscribe(
args => watcher_PositionChanged(args.Sender, args.EventArgs));

// Start the GeoCoordinateWatcher to begin receiving data from the Location Service.
watcher.Start();
}
else
{
// Start the thread on which emulated location data is generated.
// The method StartEmulation is defined next.
Thread emulationThread = new Thread(StartEmulation);
emulationThread.Start();
}

}

private void button2_Click(object sender, RoutedEventArgs e)
{

}
}
}

程序运行效果如下:

      关于反应性扩展框架,请参见MSDN:Windows Phone 的 Reactive Extensions for .NET Framework 概述 、How to: Use Reactive Extensions to Emulate and Filter Location Data for Windows Phone

      另外,《Windows Phone 7高级编程》P160、P168也提供了2中模拟位置的方法,个人以为比反应性扩展框架模拟的简单,感兴趣的博友可以自己学习一下~

      希望对大家有帮助~

Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions

原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_01/introrx_01_02.html作者:河合 宜文安装方法关于 Rx 的安装,可以通过...
  • fangxinggood
  • fangxinggood
  • 2012年05月22日 01:49
  • 9094

RxJava: Reactive Extensions for the JVM

RxJava是Reactive Extensions的Java VM实现:用于通过使用可观察序列来编译异步和基于事件的程序的库。 它扩展了观察者模式以支持数据/事件序列,并添加运算符,允许您以声明方...
  • baidu_35397148
  • baidu_35397148
  • 2017年02月06日 09:52
  • 510

Reactive Extensions (Rx) 入门(5) —— Rx的事件编程③

原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_02/introrx_02_03.html作者:河合 宜文合成用的方法本章将介绍一些Rx代表性...
  • fangxinggood
  • fangxinggood
  • 2012年07月18日 23:19
  • 5687

The Reactive Extensions for JavaScript (RxJS)

Rxjs是用于Javascript的一组库,用于构成异步的、用了可观察集合的项目,及ES5的Array#extras类型。为什么需要响应式? 应用程序,特别是web上的已经因为Ajax革命,从简单的...
  • hongmingli1357
  • hongmingli1357
  • 2016年10月08日 17:07
  • 126

【好文收藏】Reactive Extensions入门

【好文收藏】Reactive Extensions入门最近想用ReactiveUI.NET来做一个新项目,网上找了一些比较不错的资料,赶紧收藏。中文博客 Reactive Extensions入门 R...
  • derek518
  • derek518
  • 2016年11月16日 08:49
  • 419

Reactive Extensions (Rx) 入门(1) —— Reactive Extensions 概要

原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_01/introrx_01_01.html作者:河合 宜文众所周知,从 C# 3.0 开始 L...
  • fangxinggood
  • fangxinggood
  • 2012年04月15日 16:14
  • 12058

新兴趋势:反应性编程

http://www.infoq.com/cn/news/2013/08/reactive-programming-emerging InfoQ在几年以前就开始跟踪这一范式,...
  • whgggg
  • whgggg
  • 2013年09月03日 11:13
  • 1876

Reactive Extensions (Rx) 入门(4) —— Rx的事件编程②

原文:http://www.atmarkit.co.jp/fdotnet/introrx/introrx_01/introrx_02_02.html作者:河合 宜文事件是什么?用Rx来处理事件的优势让...
  • fangxinggood
  • fangxinggood
  • 2012年06月23日 23:33
  • 5920

Reactive Programming with RxJava-Chapter2:Reactive Extensions

Anatomy of rx.ObservableIndeed,Observablecan actually produce three types of events: Values of type ...
  • sxenon
  • sxenon
  • 2017年02月22日 13:12
  • 183

【RxJava】的学习(一)

RxJava是一种响应式的编程方式,一种对观察者模式的拓展,可以将对数据的操作转换为流式的操作,使得逻辑关系更简单,提高代码可读性和增强解耦性。本文需要了解Java的观察者模式作为学习前提。RxJav...
  • ChangeYahuhei
  • ChangeYahuhei
  • 2016年11月15日 21:33
  • 212
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:反应性扩展框架(Reactive Extensions)
举报原因:
原因补充:

(最多只允许输入30个字)