wpf - 为什么 Observable.range 在 GUI 线程上运行时会卡住?

标签 wpf f# system.reactive

module StackTenButtons.Try2

open System
open System.Windows
open System.Windows.Controls

open System.Reactive.Linq
open System.Reactive.Disposables
open FSharp.Control.Reactive

let control c l = 
    Observable.Create (fun (sub : IObserver<_>) ->
        let c = c()
        let d = new CompositeDisposable()
        List.iter (fun x -> d.Add(x c)) l
        sub.OnNext(c)
        d :> IDisposable
        )
let do' f c = f c; Disposable.Empty
let prop s v c = Observable.subscribe (s c) v

let w =
    control Window [
        prop (fun t v -> t.Content <- v) <| control StackPanel [
            do' (fun pan ->
                Observable.range 0 10
                |> Observable.subscribe (fun x -> pan.Children.Add(Button(Content=sprintf "Button %i" x)) |> ignore)
                |> ignore
                )
            ]
        ]

[<STAThread>]
[<EntryPoint>]
let main _ = w.Subscribe (Application().Run >> ignore); 0

我正在尝试为响应式(Reactive) UI 制作一个小型概念验证库,并且在尝试编写向父级添加多个控件的函数时遇到了这个问题。标准属性设置在单例时有效,但在使用像 Observable.range 这样的迭代器函数时则无效。

有可能实现这个功能吗?

由于 F# 需要手动将一些内容添加到项目文件中,以便可以使用 WPF,here is 是用于此目的的存储库。

最佳答案

Range 的默认调度程序是 Scheduler.CurrentThread

CurrentThreadImmediate 的行为有时会导致永久蹦床或死锁,特别是在尝试与 Observable.Create 同步使用时> 或类似的计划外冷观测。

它们锁定的确切原因很难描述,但与发现的行为类似 herehere .

 Observable.Create (fun (sub : IObserver<_>) -> 
        sub.OnNext(1)
        sub.OnNext(2)
        sub.OnNext(3)
        d :> IDisposable //<-- this dispose should cancel all `OnNext`
 )

上面的处理永远不会被调用,以防止项目被发射 - 直到项目被发射后。如果您手动构造可观察量,请尝试使其接受调度程序参数。

DispatcherScheduler 回到 Rx.NET 核心可能还需要一段时间。 下面是一个最小的 DispatcherScheduler 的实现:

type DispatcherScheduler =
    static member Instance = {
     new IScheduler with
         member _.Now = DateTimeOffset.Now
         member _.Schedule<'S>(state: 'S, action: Func<IScheduler, 'S, IDisposable>) : IDisposable = 
            let op = Application.Current.Dispatcher.InvokeAsync(fun () -> action.Invoke(DispatcherScheduler.Instance, state))
            Disposable.Create(fun () -> op.Abort() |> ignore)
         member _.Schedule<'S>(state: 'S, dueTime: TimeSpan, action: Func<IScheduler, 'S, IDisposable>) : IDisposable = failwith "Not Impl"
         member _.Schedule<'S>(state: 'S, dueTime: DateTimeOffset, action: Func<IScheduler, 'S, IDisposable>) : IDisposable = failwith "Not Impl"
    }

关于wpf - 为什么 Observable.range 在 GUI 线程上运行时会卡住?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61097363/

相关文章:

f# - 统计记录类型的成员

f# - 如何使用 FSharp API 创建集群单例?

f# - 为什么计算表达式不跨越finally block

c# - Rx 中的热连接

c# - 等待一个可观察的

wpf - 将按钮切换为单选按钮样式

c# - WPF-MVVM-将窗口标题绑定(bind)到属性

android - RXJava - 拆分和合并 Observable

c# - 对话框窗口 MVVM 方式

c# - 刷新进度条