Bea*_*ker 4 wpf events f# system.reactive
我最近问了一个问题: 在F#中重播记录的数据流,并将该代码与我在这里找到的功能的子集 结合在一起:http : //www.mattssoftwareblog.com/?p=271,看起来像这样:
#r "System.Reactive"
#r "System.CoreEx"
#r "FSharp.PowerPack"
#r "WindowsBase"
#r "PresentationCore"
#r "PresentationFramework"
#r "System.Xaml"
#r "System.Interactive.dll"
open System
open System.Linq
open System.Collections.Generic
open System.Net
open System.IO
open System.Threading
open System.Windows
open System.Windows.Input
open System.Windows.Controls
open System.Windows.Shapes
open System.Windows.Media
open System.Xaml
Run Code Online (Sandbox Code Playgroud)
我需要使用此处生成的事件(来自我之前的SO问题):
let prices = [ (0, 10.0); (1000, 10.5); (500, 9.5); (2500, 8.5); (500, 10.0); (1000, 10.5); (500, 9.5); (2500, 8.5) ]
let evt = new Event<float>()
async { for delay, price in prices do
do! Async.Sleep(delay)
evt.Trigger(price) }
|> Async.StartImmediate
evt.Publish.Add(printfn "Price updated: %A")
Run Code Online (Sandbox Code Playgroud)
用作此处随机创建的行的数据源(以下代码来自我提到的博客文章):
let create f =
Observable.Create<_>(fun x ->
f x
new System.Action((fun () -> ())))
let fromEvent (event:IEvent<_,_>) = create (fun x -> event.Add x.OnNext)
// Random Walker
let rand = Random()
let mutable m = 0.
let randomWalker() =
m <- m + (rand.NextDouble() * 10.) - 5.
m
let timer = new System.Timers.Timer()
timer.Interval <- 100.
let timerObs = (timer.Elapsed |> fromEvent).Select(fun _ -> randomWalker())
let chartWindow = new Window(Height = 600., Width = 600.)
let canvas = new Canvas()
chartWindow.Content <- canvas
chartWindow.Show()
let line xs =
let segs =
seq { for x , y in xs |> List.tail ->
LineSegment(Point(x,y), true) :> PathSegment }
let (sx, sy) = xs |> List.head
PathGeometry([PathFigure(Point(sx,sy), segs, false)])
let plot xs (path:Path) =
let now = DateTime.Now
let timeSpan = TimeSpan(0,1,0)
let width = 600.
let height = 600.
let pts = xs |> List.map (fun (x:Timestamped<float>) ->
(600.-(now - (x.Timestamp.DateTime)).TotalMilliseconds * 600. / timeSpan.TotalMilliseconds),x.Value + 300.)
path.Dispatcher.BeginInvoke(new SendOrPostCallback(fun pts -> path.Data <- line (pts :?> (float*float)list)), pts) |> ignore
let trailing (timespan:TimeSpan) (obs:IObservable<'
a>) =
obs.Timestamp()
.Scan([], fun ys x ->
let now = DateTime.Now
let timespan = timespan
x :: (ys |> List.filter (fun x -> (now - x.Timestamp.DateTime) < timespan)))
.Where(fun xs -> xs |> List.length > 1)
// Main Path
let mainPath = new Path(Stroke=Brushes.Blue, StrokeThickness=1.)
canvas.Children.Add(mainPath)
let trailingRandomsSub = (timerObs |> trailing (TimeSpan.FromSeconds(60.))).Subscribe(fun xs -> plot xs mainPath)
timer.Start()
Run Code Online (Sandbox Code Playgroud)
如果将其粘贴到交互式会话中,将会看到一条蓝线出现,该蓝线是随机生成的,而不是使用我的new evt Event。我想我的困惑是不了解如何Observable从我的电脑中制作和使用evt。基本上,我如何才能评估蓝线的数据源?
提前致谢,
鲍勃
在F#中,IEvent<'T>接口从继承IObservable<'T>。这意味着您可以在任何可观察到的地方使用F#事件。
您应用程序的最后一部分(可以记录事件,添加时间戳,用于Scan获取包含到目前为止生成的项目并绘制进度的列表)可以这样编写:
let trailingRandomsSub =
evt.Publish.Timestamp()
|> Observable.scan (fun l e -> e::l) []
|> Observable.add (fun xs -> plot xs mainPath)
Run Code Online (Sandbox Code Playgroud)
F#为某些Rx函数提供了包装器,因此您可以使用Observable.scan,它具有一些F#友好的语法。Observable.add只是的另一种语法Subscribe。
F#事件和可观察变量之间的主要区别在于,可观察变量在附加处理程序时开始。另一方面,您创建的F#事件Async.StartImmediate在StartImmediate调用该方法后立即开始(这意味着- 要使示例正常工作,您需要立即评估所有内容,或编写一个用于启动该事件的函数)。
| 归档时间: |
|
| 查看次数: |
1152 次 |
| 最近记录: |