首页 > 解决方案 > 如何从 F# 中的非阻塞异步方法更新 WPF GUI

问题描述

System.InvalidOperationException:“调用线程无法访问此对象,因为不同的线程拥有它。”

我有一个带有按钮的 WPF GUI,单击该按钮时:

  1. 启动控制动画(在 GUI 上),以及
  2. 启动后台进程以获取本地打印机队列。

我不想阻塞主线程(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。谢谢你。

标签: multithreadingasynchronousf#elmish-wpf

解决方案


我没有看过你的代码,但我认为你对 WPF 的问题的基本答案是Dispatcher类。您也可以使用 F# 的Async.SwitchToContext. 例如,请参阅这个 SO question。


推荐阅读