multithreading - 如何从 F# 中的非阻塞异步方法更新 WPF GUI
问题描述
System.InvalidOperationException:“调用线程无法访问此对象,因为不同的线程拥有它。”
我有一个带有按钮的 WPF GUI,单击该按钮时:
- 启动控制动画(在 GUI 上),以及
- 启动后台进程以获取本地打印机队列。
我不想阻塞主线程(GUI)。但是,当我尝试使用后台进程的结果更新主线程时,我的代码给出了上述错误。
如何让后台异步进程在不违反上下文且不阻塞主线程的情况下更新主线程?
open System.Printing
let GetPrinters =
let LocalPrintServer = new PrintServer()
let printQueues = LocalPrintServer.GetPrintQueues [|EnumeratedPrintQueueTypes.Local; EnumeratedPrintQueueTypes.Connections|]
let printerList =
printQueues
|> Seq.cast<PrintQueue>
|> Seq.toList
printerList
let GetPrintersAsync() =
async {
let! token = Async.StartChild(GetPrinters)
let! p = token
return p }
这是我正在使用的更新程序:
let asyncUpper =
async {
let! printerQues = GetPrintersAsync ()
return printerQues
}
// This is where the error is being displayed.
let getprinters (printers:PrintQueue list) =
printers
|> List.map (fun pq -> {fullname = pq.FullName; comment = pq.Comment; defaultPrintTicket= Some pq.DefaultPrintTicket;
description= pq.Description; isInError=pq.IsInError; isOffline=pq.IsOffline; Id= Guid.NewGuid() } )
{ m with Printers = getprinters; IsRefreshing = false }
编辑#1:以上是完整列表的简短版本。有关使用 Elmish.wpf 的完整源代码,请参阅 https://github.com/awaynemd/AsyncAndElmish。谢谢你。
解决方案
我没有看过你的代码,但我认为你对 WPF 的问题的基本答案是Dispatcher
类。您也可以使用 F# 的Async.SwitchToContext
. 例如,请参阅这个 SO question。
推荐阅读
- ssh - 运行playbook返回:ssh连接主机失败,运行ping all解决
- java - 添加失败:stat /var/lib/docker/tmp/docker-builderXYZ/myapp.jar:没有这样的文件或目录
- c# - ASP.NET Core Kestrel RequestSizeLimit 对不同用户不同?
- sql-server - 如何将数据从 Common Data Service 复制到 Azure 上的 SQL Server?
- oracle - ORA-00900: SQL 语句无效 - 在 oracle 12c 中运行包时
- dart - 如何在共享首选项中添加小部件
- c - 有人可以解释这个scanf代码的含义吗
- javascript - JS - 将键附加到匹配的数组、对象值
- java - 从 JAVA 运行 TCL 脚本
- javascript - 使用 npm 进行不可复制的安装