Wpf 如何在使用反应式扩展时管理副作用命令? 模块计数器应用程序 开放系统 开放系统 打开System.Windows.Controls 打开System.Windows.Media 开放系统.Reactive.Linq 开放式系统、反应式、一次性 打开FSharp.Control.Reactive ///订户 让我们做'fc=fc;一次性的,空的 让prop svc=Observable.subscribe(sc)v 让事件sfc=(sc:IEvent).Subscribe(乐趣v->fcv) 让孩子们清除addset(v1:IObservable)c=//注意:这个的早期版本有bug。 设v2_disp=new SerialDisposable() 新型复合可降解材料( v1.订阅(乐趣v2-> 清除c v2_disp 让我 v3_disp.Add if i'(c:unit->'a)l= 创建(乐趣(sub:IObserver)-> 设c=c() 设d=新的CompositeDisposable() List.iter(funx->d.Add(xc))l sub.OnNext(c) d:>IDisposable ) 设control cl=control'cl:?>IObservable 让stack\u panel'props childs=控制StackPanel(List.append props[fun c->ui\u element\u collection childs c.childs]) 让stack_panel props childs=stack_panel的props(ofSeq childs |>Observable.single可观察) let window props content=control'窗口(List.append props[prop(fun t v->t.content Observable.scanInit init)(fun model msg-> 配味精 |增量->{model with Count=model.Count+model.Step} |减量->{model with Count=model.Count-model.Step} |重置->初始化 |SetStep n->{model with Step=n} |TimerToggle on->{model with TimerOn=on} |TimedTick->if model.TimerOn然后{model with Count=model.Count+model.Step}else model ) |>可观测的.startWith[init] let timerCmd()= 更新 |>Observable.map(乐趣x->x.TimerOn) |>可观察的,可辨别的 |>Observable.CombineTest(Observable.interval(TimeSpan.FromSeconds(1.0))) |>Observable.subscribe(乐趣,时间)-> 如果是timerOn,则是Application.Current.Dispatcher.Invoke(fun()->dispatch TimedTick) ) 让我们来看= 窗口[do](乐趣t->t.标题p.垂直对齐b.内容发送增量) ] 控制按钮[ do'(乐趣b->b.内容发送减量) ] 控制边界[ do'(趣味b->b.填充b.儿童l.内容c.IsChecked Observable.map(趣味模型->模型时间)) 事件(fun c->c.已选中)(fun c v->dispatch(TimerToggled true)) 事件(fun c->c.Unchecked)(fun c v->dispatch(TimerToggled false)) ] ] ] 控制滑块[ do'(乐趣s->s.最小浮动) 事件(fun s->s.ValueChanged)(fun c v->dispatch(设置步骤(int v.NewValue))) ] 控制标签[ do'(趣味l->l.HorizontalAlignment l.Content Observable.map(趣味模型->sprintf“步长:%d”模型步长)) ] 控制按钮[ do'(乐趣b->b.HorizontalAlignment模型初始) 事件(乐趣b->b.点击)(乐趣b v->调度重置) ] ] ] [] [] 让main= 设a=Application() 使用_u=view.Subscribe(fun w->a.MainWindow

Wpf 如何在使用反应式扩展时管理副作用命令? 模块计数器应用程序 开放系统 开放系统 打开System.Windows.Controls 打开System.Windows.Media 开放系统.Reactive.Linq 开放式系统、反应式、一次性 打开FSharp.Control.Reactive ///订户 让我们做'fc=fc;一次性的,空的 让prop svc=Observable.subscribe(sc)v 让事件sfc=(sc:IEvent).Subscribe(乐趣v->fcv) 让孩子们清除addset(v1:IObservable)c=//注意:这个的早期版本有bug。 设v2_disp=new SerialDisposable() 新型复合可降解材料( v1.订阅(乐趣v2-> 清除c v2_disp 让我 v3_disp.Add if i'(c:unit->'a)l= 创建(乐趣(sub:IObserver)-> 设c=c() 设d=新的CompositeDisposable() List.iter(funx->d.Add(xc))l sub.OnNext(c) d:>IDisposable ) 设control cl=control'cl:?>IObservable 让stack\u panel'props childs=控制StackPanel(List.append props[fun c->ui\u element\u collection childs c.childs]) 让stack_panel props childs=stack_panel的props(ofSeq childs |>Observable.single可观察) let window props content=control'窗口(List.append props[prop(fun t v->t.content Observable.scanInit init)(fun model msg-> 配味精 |增量->{model with Count=model.Count+model.Step} |减量->{model with Count=model.Count-model.Step} |重置->初始化 |SetStep n->{model with Step=n} |TimerToggle on->{model with TimerOn=on} |TimedTick->if model.TimerOn然后{model with Count=model.Count+model.Step}else model ) |>可观测的.startWith[init] let timerCmd()= 更新 |>Observable.map(乐趣x->x.TimerOn) |>可观察的,可辨别的 |>Observable.CombineTest(Observable.interval(TimeSpan.FromSeconds(1.0))) |>Observable.subscribe(乐趣,时间)-> 如果是timerOn,则是Application.Current.Dispatcher.Invoke(fun()->dispatch TimedTick) ) 让我们来看= 窗口[do](乐趣t->t.标题p.垂直对齐b.内容发送增量) ] 控制按钮[ do'(乐趣b->b.内容发送减量) ] 控制边界[ do'(趣味b->b.填充b.儿童l.内容c.IsChecked Observable.map(趣味模型->模型时间)) 事件(fun c->c.已选中)(fun c v->dispatch(TimerToggled true)) 事件(fun c->c.Unchecked)(fun c v->dispatch(TimerToggled false)) ] ] ] 控制滑块[ do'(乐趣s->s.最小浮动) 事件(fun s->s.ValueChanged)(fun c v->dispatch(设置步骤(int v.NewValue))) ] 控制标签[ do'(趣味l->l.HorizontalAlignment l.Content Observable.map(趣味模型->sprintf“步长:%d”模型步长)) ] 控制按钮[ do'(乐趣b->b.HorizontalAlignment模型初始) 事件(乐趣b->b.点击)(乐趣b v->调度重置) ] ] ] [] [] 让main= 设a=Application() 使用_u=view.Subscribe(fun w->a.MainWindow,wpf,f#,system.reactive,Wpf,F#,System.reactive,是的,可以在流中分流间隔计时器。 我们可以投射到空通知或间隔的可观察对象上,然后切换到最新发出的可观察对象 let model = { Count = 0; Step = 0; TimerOn = false } let update = Subject.behavior model update |> Observable.distinctUntilChangedKey (fun x -> x.TimerOn) |> Observable.map (fun x ->

是的,可以在流中分流间隔计时器。 我们可以投射到空通知或间隔的可观察对象上,然后
切换到最新发出的可观察对象

let model = { Count = 0; Step = 0; TimerOn = false }
let update = Subject.behavior model

update
|> Observable.distinctUntilChangedKey (fun x -> x.TimerOn)
|> Observable.map (fun x -> 
    if x.TimerOn then 
        Observable.interval(TimeSpan.FromSeconds(1.0)) 
    else 
        Observable.empty
)
|> Observable.switch
|> Observable.subscribe (fun i -> printfn "Tick %d" i)
|> ignore

while true do
    printfn "Start (y)?"
    let switch = Console.ReadLine()
    update 
    |> Subject.onNext( { model with TimerOn = switch = "y" })
    |> ignore
输出

Start (y)?
y
Start (y)?
Tick 0
Tick 1
Tick 2
Tick 3
n
Start (y)?
y
Start (y)?
Tick 0
Tick 1

正如您所看到的,计时器确实会在您需要的时候重新启动。

是的,可以将间隔计时器分流到流中或从流中分流出来。 我们可以投射到空通知或间隔的可观察对象上,然后
切换到最新发出的可观察对象

let model = { Count = 0; Step = 0; TimerOn = false }
let update = Subject.behavior model

update
|> Observable.distinctUntilChangedKey (fun x -> x.TimerOn)
|> Observable.map (fun x -> 
    if x.TimerOn then 
        Observable.interval(TimeSpan.FromSeconds(1.0)) 
    else 
        Observable.empty
)
|> Observable.switch
|> Observable.subscribe (fun i -> printfn "Tick %d" i)
|> ignore

while true do
    printfn "Start (y)?"
    let switch = Console.ReadLine()
    update 
    |> Subject.onNext( { model with TimerOn = switch = "y" })
    |> ignore
输出

Start (y)?
y
Start (y)?
Tick 0
Tick 1
Tick 2
Tick 3
n
Start (y)?
y
Start (y)?
Tick 0
Tick 1

正如你所看到的,计时器确实会在你想要的时候重新启动。

很有趣。我在一本书中读到了
开关
,但我认为它只选择了两个观察值中最新的一个。这一个更有用。
distinctUntilChangedKey
也是我应该使用的东西。我认为
开关映射
也可以在这里使用,但情况似乎并非如此。为此,我必须在F#repo上提出一个问题。这解决了我一半的问题。另一个问题是命令的设计考虑。我想知道是否有一种好方法可以将其作为更新
管道的一部分?我需要类似于
iter
的东西,像identity函数一样作用于模型n并只传递它,但在内部是有状态的,如
scan
。不需要在
main
中单独订阅
timerCmd
。实现这样的东西并不太难,但我不确定是否应该。也许命令处理程序是与像我现在这样的更新视图1实际上是一个理想的设计。反应式扩展的设计正是功能性和命令性的适当数量。拥有具有复杂内部状态的组合器将与此相反。有趣的是,他们似乎自己实现了
switchMap
,而这并不是一个非常正确的实现。Id实际上,整个UI都可以声明性地建模为一系列描述行为和动作的反应式组合符。这在反应式UI中相当成功。但总有一些边缘情况。选择您认为可能导致数量减少的方法