Barra de progresso com assíncrona em FsXaml aplicação

0

Pergunta

No meu F# (FsXaml/Code-Behind) aplicação, eu gostaria de usar uma barra de progresso sem a utilização de um trabalho de fundo como eu fazer em C#. Baseado em um artigo na internet (o link está aqui), eu tentei usar assíncrona fluxos de trabalho.

Eu criei com base em código (em certa medida) nos exemplos, no referido artigo, mas não funcionou como eu esperava. O atual thread (thread de INTERFACE de utilizador) ainda está bloqueado, como se nenhum código assíncrono estava lá. Sem mudar para um segmento de plano de fundo ocorre. A barra de progresso é ativada apenas depois de longa operação foi concluída. Remover o onThreadPool função não tem efeito.

A minha pergunta é: o Que está errado no meu código e como fazê-lo direito?

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

Melhor resposta

3

Há uma série de coisas erradas com o seu código.

  • Primeiro, em progressBar(), longRunningOperation() você realmente chamar a operação longa e por isso tudo é executado aqui. (Tanto quanto eu posso adivinhar a partir do seu incompleta da amostra, esta é apenas uma chamada de função, não de outra operação assíncrona).

  • Você, em seguida, passar os resultados operation e progress ao redor, mas essas são apenas unit valores que, na verdade, não fazer nada.

  • Consequentemente, a operação assíncrona async { operation } que você passar para onThreadPool não fazer nada.

  • No doBusyAsync, você usa Async.StartImmediate para executar a operação em um bloqueio de forma (assim que este seria bloquear o thread, mesmo se ele foi executando alguma operação real).

  • Além de ser o bloqueio, você também não precisa async { do! operation } porque isso é o equivalente a pouco operation.

Em resumo, o código de alguma forma tem uma maneira muito complexa. Você deve simplificá-lo para algo muito básico, como um primeiro passo. Eu não tenho o direito de configuração para tentar isso, mas eu acho que algo como o seguinte deve fazer o truque:

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)

Eu removi todos inútil, funções e passagem de parâmetro e simplificado, tanto quanto possível - é apenas a sua operação longa, que é chamado diretamente a partir de async uma vez ele muda para o pool de threads. Você obter o seu resultado e, depois de mudar de volta para o contexto original, deve ser capaz de mostrar que na sua interface do usuário. Idealmente, você faria o longRunningOperation si assíncrona (e chamá-lo usando let!), mas acima deve funcionar.

2021-11-24 00:15:43
0

Para resumir as coisas, eu tenho estendido Tomáš Petříček do código com o código relacionado com a operação longa baseado em Jim Foye comentário (cerca de salto para trás no thread da INTERFACE do usuário). O código agora funciona como um encanto. Meus agradecimentos a Tomáš Petříček para o seu tipo e a resposta detalhada.

    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

Em outros idiomas

Esta página está em outros idiomas

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