Barra de progreso con async en FsXaml aplicación

0

Pregunta

En mi F# (FsXaml/Código Detrás) de la aplicación, me gustaría usar una barra de progreso sin la utilización de un fondo trabajador como yo lo hago en C#. Basado en un artículo en internet (el enlace está aquí), he intentado utilizar flujos de trabajo asincrónicos.

He creado el código (en cierta medida) en los ejemplos en el artículo citado, pero no funcionó como yo esperaba. El subproceso actual (subproceso de interfaz de usuario) está todavía bloqueado como si no código asincrónico estaba allí. No tienes que cambiar a un subproceso de fondo se produce. La barra de progreso se activa sólo después de la larga marcha de la operación ha sido terminada. La eliminación de la onThreadPool función no tiene ningún efecto.

Mi pregunta es: ¿Cuál es el error en mi código y cómo hacer lo correcto?

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

Mejor respuesta

3

Hay un número de cosas mal con su código.

  • En primer lugar, en progressBar(), longRunningOperation() usted llamar a la larga ejecución de la operación y por tanto todo se ejecute aquí. (Por lo que puedo adivinar por su incompleta de la muestra, esto es sólo una llamada a una función, y no otra operación asincrónica).

  • A continuación, pasar los resultados operation y progress a su alrededor, pero esas son las unit valores que en realidad no hacen nada.

  • En consecuencia, la operación asincrónica async { operation } que le pasa onThreadPool no hacer nada en absoluto.

  • En doBusyAsync, utilizar Async.StartImmediate para ejecutar la operación en un bloqueo de forma (por lo que este bloque el hilo, incluso si se estaba ejecutando algunos reales de la operación).

  • Aparte de ser el bloqueo, usted también no necesita async { do! operation } porque esto es equivalente a sólo operation.

En resumen, el código de alguna manera consiguió muy complejo. Usted debe simplificar a algo tan básico como el primer paso. Yo no tengo el derecho de configuración para probar esto, pero creo que algo como lo siguiente debe hacer el truco:

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)

He quitado todos los inútiles funciones y paso de parámetros y simplificado tanto como sea posible - es sólo su larga ejecución de la operación, que se llama directamente desde async una vez que se cambia al hilo de la piscina. Usted obtener su resultado y, después de volver a cambiar el contexto original, debe ser capaz de mostrar que en su interfaz de usuario. Idealmente, sería hacer el longRunningOperation sí asincrónica (y lo llaman el uso de let!) pero lo anterior debería funcionar.

2021-11-24 00:15:43
0

Para resumir las cosas de arriba, he ampliado Tomáš Petříček del código con el código relacionado con la operación de ejecución prolongada basado en Jim Foye comentario (sobre saltando de nuevo en el subproceso de interfaz de usuario). El código ahora funciona como un encanto. Mi agradecimiento a Tomáš Petříček por su amable y detallada respuesta.

    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

En otros idiomas

Esta página está en otros idiomas

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