Pokrok bar s async v FsXaml aplikace

0

Otázka

V mé F# (FsXaml/Code Behind) aplikace, chtěl bych použít progress bar bez využití zázemí pracovníka, jak udělám v C#. Na základě článku na internetu (odkaz je tady), jsem se snažil použít asynchronní pracovní postupy.

Vytvořil jsem kód založený (do jisté míry) na příklady ve výše zmíněném článku, ale to nefungovalo, jak jsem čekal. Aktuální vlákno (UI vlákno) je stále blokována, jako kdyby žádná asynchronní kód tam byl. Žádné přepínání na pozadí nit dochází. Progress bar je aktivován pouze po dlouho běžící operace byla dokončena. Odstranění onThreadPool funkci nemá žádný vliv.

Moje otázka je: Co je špatně v mém kódu a jak to napravit?

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

Nejlepší odpověď

3

Existuje několik věcí špatně s váš kód.

  • Za prvé, v progressBar(), longRunningOperation() skutečně nazvat dlouho běžící operace a tak to všechno dostane. (Pokud můžu hádat z vaší neúplné vzorek, je to jen volání funkce, ne další asynchronní operace).

  • Ty pak předat výsledky operation a progress kolem, ale to jsou jen unit hodnoty, které nejsou ve skutečnosti dělat nic.

  • Z toho vyplývá, že asynchronní operace async { operation } to, co jste projít k onThreadPool nemusí dělat vůbec nic.

  • V doBusyAsyncmůžete použít Async.StartImmediate spustit provoz v blokování způsobem (takže by to mohl blokovat vlákno, i když to byl spuštěn nějaký skutečný provoz).

  • Kromě toho, že blokování, také nemusíte async { do! operation } protože to je stejné, jen operation.

Stručně řečeno, váš kód nějak příliš složité. Ty by měly zjednodušit, aby to něco velmi základní jako první krok. Nemám správné nastavení vyzkoušet, ale myslím, že něco podobného by mělo stačit:

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)

Odstranil jsem všechny zbytečné funkce a předávání parametrů a zjednodušený to, stejně jako je to možné - je to jen vaše dlouho běžící operace, která je volána přímo z async jakmile to přepne do fondu podprocesů. Dostanete svůj výsledek a po přepnutí zpět na původní kontext, by měl být schopen displej, který ve svém uživatelském rozhraní. V ideálním případě by se longRunningOperation sám asynchronní (a call to pomocí let!), ale výše uvedené by mělo fungovat.

2021-11-24 00:15:43
0

Chcete-li součet věci, mám rozšířené Tomáš Petříček je kód s kód vztahující se k dlouhotrvající operace na základě Jim Foye komentář (o skočení zpět na UI vlákně). Ten kód funguje jako kouzlo. Děkuji Tomáš Petříček pro jeho laskavý a podrobnou odpověď.

    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

V jiných jazycích

Tato stránka je v jiných jazycích

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