Barra di avanzamento con async in FsXaml applicazione

0

Domanda

Nel mio F# (FsXaml/Codice Dietro) applicazione, vorrei utilizzare una barra di avanzamento, senza l'utilizzo di un operaio di sfondo come faccio in C#. Basato su un articolo su internet (il link è qui), ho provato a utilizzare flussi di lavoro asincroni.

Ho creato il codice di base (in certa misura) su esempi riportati nel predetto articolo, ma non ha funzionato come mi aspettavo. Il thread corrente (UI thread) è ancora bloccato, come se non async codice che c'era. Nessuna commutazione a un thread in background si verifica. La barra di avanzamento viene attivato solo dopo una lunga esecuzione operazione è stata completata. Rimozione del onThreadPool funzione non ha alcun effetto.

La mia domanda è: Cosa c'è di sbagliato nel mio codice, e come farlo giusto?

type MainWindowXaml = FsXaml.XAML<"XAMLAndCodeBehind/MainWindow.xaml">

type MainWindow() as this =

    inherit MainWindowXaml()

    //....some code....

    let ButtonClick _ = 
   
        //....some code....
       
        let longRunningOperation() = //....some long running operation (reading from Google Sheets)....            
             
        let progressBar() = this.ProgressBar.IsIndeterminate <- true     

        let doBusyAsync progress operation =  
            progress
            async
                {   
                  do! operation
                }
            |> Async.StartImmediate 
    
        let onThreadPool operation =
            async
                {    
                  let context = System.Threading.SynchronizationContext.Current
                  do! Async.SwitchToThreadPool()
                  let! result = operation
                  do! Async.SwitchToContext context
                  return result
                } 
    
        let asyncOperation progress operation =   
            async { operation } 
            |> onThreadPool
            |> doBusyAsync progress 
    
        (progressBar(), longRunningOperation()) ||> asyncOperation 
      
    do
        //....some code....
        this.Button.Click.Add ButtonClick
asynchronous f# fsxaml
2021-11-23 23:13:28
2

Migliore risposta

3

Ci sono un certo numero di cose sbagliate con il tuo codice.

  • Primo, in progressBar(), longRunningOperation() si chiama effettivamente operazione lunga esecuzione e così tutto diventa eseguire qui. (Per quanto posso intuire dal vostro campione incompleto, questa è solo una chiamata di funzione, non un'altra operazione asincrona).

  • È quindi possibile passare i risultati operation e progress in giro, ma quelli sono solo unit valori che in realtà non fare nulla.

  • Di conseguenza, l'operazione asincrona async { operation } che si passa a onThreadPool non fare nulla a tutti.

  • In doBusyAsyncutilizzare Async.StartImmediate per eseguire l'operazione in un blocco di modo (quindi questo potrebbe bloccare il thread, anche se era in esecuzione un po ' operazione).

  • A parte il blocco, inoltre non è necessario async { do! operation } perché questo è l'equivalente di appena operation.

In sintesi, il codice ottenuto in qualche modo troppo complesso. Si dovrebbe semplificare qualcosa di molto di base, come primo passo. Non ho il diritto di installazione di provare questo, ma penso che qualcosa di simile dovrebbe fare il trucco:

let ButtonClick _ = 
  let longRunningOperation() = 
    // some long-running operation

  let asyncOperation() = async {
    // Start the progress bar here
    let context = System.Threading.SynchronizationContext.Current
    do! Async.SwitchToThreadPool()
    let result = longRunningOperation()
    do! Async.SwitchToContext context
    // Display the 'result' in your user interface
    // Stop the progress bar here
  }

  Async.Start(asyncOperation)

Ho rimosso tutto inutile funzioni e passaggio di parametri e semplificata, per quanto possibile, ma è solo una operazione lunga esecuzione, che è chiamato direttamente da async una volta che si passa al pool di thread. Si ottenere il risultato e, dopo aver cambiato il contesto originale, dovrebbe essere in grado di visualizzare nell'interfaccia utente. Idealmente, si farebbe il longRunningOperation stessa asincrona (e chiamare utilizzando let!) ma sopra dovrebbe funzionare.

2021-11-24 00:15:43
0

Per riassumere le cose, ho esteso la Tomáš Petříček codice con il codice relativo a lungo il funzionamento basato su Jim Foye commento (circa saltellando sul thread dell'interfaccia utente). Ora il codice funziona come un fascino. Il mio grazie a Tomáš Petříček per la sua gentile e dettagliata risposta.

    let low = string (this.TextBox2.Text)
    let high = string (this.TextBox3.Text)
    let path = string (this.TextBox4.Text)

    (* longRunningOperation() replaced by textBoxString4() and textBoxString3() 
       based on the comment by Jim Foye
    
    let longRunningOperation() = 
        async
            {
              match textBoxString4 low high >= 0 with
              | false -> this.TextBox1.Text <- textBoxString3 low high path 
              | true  -> this.TextBox1.Text <- "Chybný rozdíl krajních hodnot"        
            }
    *)

    let textBoxString4() = 
        async
            {
              let result = textBoxString4 low high
              return result
            }                  
                           
    let textBoxString3() =        
        async
            {
              //the actual long running operation (reading data 
              //from Google Sheets)
              let result = textBoxString3 low high path 
              return result
            }  

    let asyncOperation() = 
        async
            {
              let context = System.Threading.SynchronizationContext.Current
              this.ProgressBar2.IsIndeterminate <- true
              do! Async.SwitchToThreadPool()
              (*let! result = longRunningOperation() throws an exception 
              "The calling thread cannot access this object because
               a different thread owns it." 
              *)
              let! result4 = textBoxString4()  
              let! result3 = textBoxString3()  
              do! Async.SwitchToContext context
              match result4 >= 0 with
              | false -> this.TextBox1.Text <- result3
              | true  -> this.TextBox1.Text <- "Chybný rozdíl krajních hodnot" 
              this.ProgressBar2.IsIndeterminate <- false
            } 
    Async.StartImmediate(asyncOperation())//not working with Async.Start
                                             
2021-11-24 18:29:36

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................