gpt4 book ai didi

multithreading - WinForms App 中的 F# 跨线程 UI 异常

转载 作者:行者123 更新时间:2023-12-04 06:40:59 24 4
gpt4 key购买 nike

我在 F# 中开发一个简单的应用程序时遇到问题,该应用程序仅读取请求的 HTML 页面的长度。

似乎在开发 UI 应用程序时,VB.NET/C# 语言也会出现类似的错误。

enter image description here

但我对 F# 还是比较陌生,并没有真正想象在 F# 中完全解决此类问题的热度。

F#中的源代码:

http://pastebin.com/e6WM0Sjw

open System
open System.Net
open Microsoft.FSharp.Control.WebExtensions
open System.Windows.Forms

let form = new Form()
let text = new Label()
let button = new Button()

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
"MSDN", "http://msdn.microsoft.com/"
"Bing", "http://www.bing.com"
]

let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
text.Text <- String.Format("Read %d characters for %s", html.Length, name)
with
| ex -> printfn "%s" (ex.Message);
}

let runAll() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
|> ignore

form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Test download tool"

text.Width <- 200
text.Height <- 50
text.Top <- 0
text.Left <- 0
form.Controls.Add(text)

button.Text <- "click me"
button.Top <- text.Height
button.Left <- 0
button.Click |> Event.add(fun sender -> runAll() |> ignore)
form.Controls.Add(button)

[<STAThread>]
do Application.Run(form)

此致,

谢谢!

最佳答案

您必须将线程上下文从 Async ThreadPool 切换到 UI 线程更新前 text.Text属性(property)。见 MSDN link对于 F# 异步特定的解释。

通过捕获 UI 上下文修改您的代码段后

let uiContext = System.Threading.SynchronizationContext()

放在您的 let form = new Form() 之后声明和更改 fetchAsync定义为
let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
do! Async.SwitchToContext(uiContext)
text.Text <- text.Text + String.Format("Read {0} characters for {1}\n", html.Length, name)
with
| ex -> printfn "%s" (ex.Message);
}

它可以正常工作。

更新:在与同事讨论调试器特性后,他强调需要干净地操作 UI 上下文,以下修改现在与运行方式无关:
open System
open System.Net
open Microsoft.FSharp.Control.WebExtensions
open System.Windows.Forms
open System.Threading

let form = new Form()
let text = new Label()
let button = new Button()

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
"MSDN", "http://msdn.microsoft.com/"
"Bing", "http://www.bing.com"
]

let fetchAsync(name, url:string, ctx) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
do! Async.SwitchToContext ctx
text.Text <- text.Text + sprintf "Read %d characters for %s\n" html.Length name
with
| ex -> printfn "%s" (ex.Message);
}

let runAll() =
let ctx = SynchronizationContext.Current
text.Text <- String.Format("{0}\n", System.DateTime.Now)
urlList
|> Seq.map (fun(site, url) -> fetchAsync(site, url, ctx))
|> Async.Parallel
|> Async.Ignore
|> Async.Start

form.Width <- 400
form.Height <- 300
form.Visible <- true
form.Text <- "Test download tool"

text.Width <- 200
text.Height <- 100
text.Top <- 0
text.Left <- 0
form.Controls.Add(text)

button.Text <- "click me"
button.Top <- text.Height
button.Left <- 0
button.Click |> Event.add(fun sender -> runAll() |> ignore)
form.Controls.Add(button)

[<STAThread>]
do Application.Run(form)

关于multithreading - WinForms App 中的 F# 跨线程 UI 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20590982/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com