繁体   English   中英

F# 使异步工作流的结果可供 UI 线程显示

[英]F# Making the result of an async workflow available to be displayed by the UI thread

我正在尝试启动需要等待登录到外部系统的 window,因此我想异步处理此登录。 我已经在 F# 交互式 window 中实现了这一点,并且一切都按预期运行,但是当我在程序中运行代码时出现错误:

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

F# 交互:

#r "WindowsBase"
#r "PresentationCore"
#r "PresentationFramework"

open System
open System.Threading
open System.Windows

let loginTask = async {
    Console.WriteLine "Logging in"
    Thread.Sleep(5000)
    let user = "MyUser"
    Console.WriteLine ("Logged in as " + user)
    return user
}

let createWindow () =
    Console.WriteLine "Creating window"
    let window = Window()
    window.Title <- "MyWindow"
    window.Show()
    window

let runWindowWithUser (window:Window) user =
    window.Title <- (user + "'s Window")
    Console.WriteLine ("Running " + window.Title + " as " + user)

let mainAsync = async {
    let window = createWindow()

    let! userToken = loginTask |> Async.StartChild
    let! user = userToken 

    runWindowWithUser window user
    }

do mainAsync |> Async.StartImmediate

程序.fs

open System.Threading
open System.Windows

[<EntryPoint; STAThread>]
let main argv =

    let loginTask = async {
        Console.WriteLine "Logging in"
        Thread.Sleep(5000)
        let user = "MyUser"
        Console.WriteLine ("Logged in as " + user)
        return user
    }
    
    let createWindow () =
        Console.WriteLine "Creating window"
        let window = Window()
        window.Title <- "MyWindow"
        window.Show()
        window
    
    let runWindowWithUser (window:Window) user =
        window.Title <- (user + "'s Window")
        Console.WriteLine ("Running " + window.Title + " as " + user)
    
    let mainAsync = async {
        let window = createWindow()
    
        let! userToken = loginTask |> Async.StartChild
        let! user = userToken 
    
        runWindowWithUser window user
        }
    
    do mainAsync |> Async.StartImmediate

    Console.ReadKey()

    1

我明白了, let! 可能导致工作流的 rest 在后台线程上继续,所以我尝试交换线程:

    let mainAsync = async {
        let context = SynchronizationContext.Current
        let window = createWindow()
    
        do! Async.SwitchToThreadPool()
        let! user = loginTask
        
        do! Async.SwitchToContext context
        runWindowWithUser window user
    }

但这似乎并没有像我预期的那样变回原来的线程。

我还尝试将所有 UI 代码排除在异步工作流程之外以避免处理线程,但是我不确定如何从后台线程上完成的工作中获取我的user信息

let loginTask = async {
    Console.WriteLine "Logging in"
    Thread.Sleep(5000)
    let user = "MyUser"
    Console.WriteLine ("Logged in as " + user)
    return user
}

Console.WriteLine "Creating window"
let window = Window()
window.Title <- "MyWindow"
window.Show()

let user = loginTask|> Async.StartImmediate   // How do I get user information from loginTask without using let! that must be called from an async workflow?

window.Title <- (user + "'s Window")
Console.WriteLine ("Running " + window.Title + " as " + user)

我对 F# 和一般的函数式编程非常陌生。 如何从后台线程上的登录代码中获取user信息到 UI 线程,以及为什么 F# 交互式 window 中的线程行为不同?

这是我的代码,我删除了 Console.Writeline() 调用,您只需用记录器调用(或 Debug.WriteLine() 或其他)替换它们。

open System
open System.Threading
open System.Windows

let createWindow() =
    let window = Window()
    window.Title <- "MyWindow"
    window.Show()
    window

let runWindowWithUser (window: Window) user =
    window.Title <- (user + "'s Window")

let loginTask = 
    async {
        Thread.Sleep(1000)
        let user = "MyUser"
        return user
    }
    
[<EntryPoint; STAThread>]
let main _ =
    let app = Application()
    app.MainWindow <- createWindow()

    app.Startup.Add (fun _ ->
        async {
            let context = SynchronizationContext.Current
            do! Async.SwitchToThreadPool()
            let! user = loginTask
            do! Async.SwitchToContext context
            runWindowWithUser app.MainWindow user
        } |> Async.StartImmediate
    )

    app.Run()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM