Barre de progression avec async en FsXaml application

0

La question

Dans mon F# (FsXaml/Code-Behind) de l'application, je voudrais utiliser une barre de progression sans l'utilisation d'un arrière-plan travailleur comme je le fais en C#. Basé sur un article sur internet (le lien est ici), j'ai essayé d'utiliser asynchrone des flux de travail.

J'ai créé la fonction de code (un peu) sur les exemples dans l'article mentionné ci-dessus, mais cela n'a pas fonctionné comme je l'avais prévu. Ce thread (thread d'INTERFACE utilisateur) est toujours bloqué comme si async code était là. Pas de changement à un thread d'arrière-plan se produit. La barre de progression est activée qu'après la longue course de l'opération a été terminée. Retrait de la onThreadPool fonction n'a aucun effet.

Ma question est: Quel est le problème dans mon code et comment le faire?

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

La meilleure réponse

3

Il y a un certain nombre de choses de mal avec votre code.

  • Tout d'abord, dans progressBar(), longRunningOperation() vous avez fait appel au long de l'exécution de l'opération et ce qu'il en est exécuté ici. (Autant que je peux le deviner à partir de votre incomplète de l'échantillon, c'est juste un appel de fonction, pas une autre opération asynchrone).

  • Vous passez ensuite les résultats operation et progress autour, mais ce sont juste des unit les valeurs qui ne sont pas réellement faire quelque chose.

  • Par conséquent, l'opération asynchrone async { operation } que vous passez à onThreadPool ne rien faire du tout.

  • Dans doBusyAsyncvous utilisez Async.StartImmediate pour exécuter l'opération dans un blocage de la voie (donc, ce serait de bloquer le thread, même si c'était de l'exécution de certains réelles de fonctionnement).

  • En plus d'être de blocage, vous aussi n'avez pas besoin async { do! operation } parce que c'est l'équivalent d'un peu operation.

En résumé, votre code obtenu en quelque sorte trop complexe. Vous devez simplifier à quelque chose de très basique comme la première étape. Je n'ai pas le droit d'installation pour essayer cela, mais je pense que quelque chose comme ce qui suit devrait faire l'affaire:

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)

J'ai enlevé toutes les fonctions inutiles et passage de paramètres et simplifié autant que possible - il est juste de votre opération longue à exécuter, qui est appelée directement à partir de async une fois qu'il passe en pool de threads. Vous obtenez votre résultat, et, après être repassé au contexte d'origine, doit être en mesure d'afficher dans votre interface utilisateur. Idéalement, vous auriez du faire le longRunningOperation lui-même asynchrone (et de l'appeler à l'aide let!) mais la ci-dessus devrait fonctionner.

2021-11-24 00:15:43
0

Pour résumer les choses, j'ai étendu Tomáš Petříček du code avec le code lié à la longue est en cours d'exécution basée sur Jim Foye commentaire (environ saut arrière sur le thread d'INTERFACE utilisateur). Le code fonctionne maintenant comme un charme. Mes remerciements à Tomáš Petříček de son genre et de la réponse détaillée.

    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

Dans d'autres langues

Cette page est dans d'autres langues

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