簡體   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