Blazor Wartemeldung während Button Click

Wenn es mal länger dauert sollte man seinen Benutzer mit einer Wartemeldung die Ungeduld nehmen, dauernd auf den verdammten Button klicken zu müssen. Man würde meinen das ist ganz einfach. Ein Spinner animiertes Gif und Visibilty und fertig. Ist es nicht und daran ist das Rendering bei einer Blazor Server Anwendung schuld, weil die manchmal Nebeneffekte zeigt.

Das UI mit Boostrap 5 hat eine einfache Lösung für eine Spinner Load Message.

   1:   <button ID="showactivity"
   2:            @onclick="showactivity" disabled=@(!ShowActivityVisible)
   3:            class="btn btn-outline-info">
   4:            @if (!ShowActivityVisible)
   5:              {
   6:              <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
   7:              <span class="visually-hidden">Loading...</span>
   8:               }
   9:     show activity
  10:  </button>

Das sollte dann so aussehen

activity

In diesem Fall wird ein HTTP Request ausgelöst und eine Web Api abgefragt, was naturgemäß länger dauern kann. Man kann am Anfang des Button Click Handler Code die Variable Show… (oder isvisible) auf false setzen und bei verlassen auf true. Hier grätscht das Rendering rein, das nicht innerhalb einer Funktion ausgelöst wird. Rendering einer Component kann man per StateHasChanged erzwingen. Löst das Problem auch nicht, weil hier Nebenläufigkeiten in Tasks auftreten. Also Blazor wird das UI updaten, wenn die andere Aufgabe (HttpRequest) fertig ist. Dann ist es natürlich zu spät.

Wenn man den Button Click Handler selbst asynchron ausleget, ist man auf den richtigen Weg. Allerdings muss dann noch irgendwas async laufen. Der HttpClient Get wäre dafür prädestiniert, wird aber wegen seiner Risken in einen Try Catch Block gelegt und kann dann nicht per await genutzt werden.

Die Lösung um den Spinner Wartedeilaog im Button Click beim laden einer langen Liste zu zeigen -Fake Task in Zeile 4

   1:   async void showactivity()
   2:  {
   3:     ShowActivityVisible = false;
   4:     await Task.Delay(1);
   5:     try
   6:       {
   7:       var client = ClientFactory.CreateClient();
   8:      var res = client.GetAsync($@"http://ppedv.de/api/email").Result;
   9:       if (res.IsSuccessStatusCode)
  10:        {
  11:         try
  12:           {
  13:            var nl = res.Content.ReadFromJsonAsync<List<UrlClickTrace>>().Result;
  14:            ListeClicks = nl.OrderByDescending(x => x.Datum).ToList();
  15:           }
  16:         catch
  17:         {        }
  18:     }
  19:    }
  20:    catch
  21:    {        }
  22:  ShowActivityVisible = true;
  23:  StateHasChanged();
  24:      }

Nebenbemerkung: in .NET Framework wurde noch die Methode ReadAsAsync aus NewtonSoft.Json genutzt. Da .NET 6 core stattdessen auf System.Json als JSON Parser setzt, lautet die Methode nun ReadFromJosnAsync um aus einer Json Anwort automatisch in einer generische Liste zu decoden.

Kommentare sind geschlossen