Blazor WebAssembly, Teil 2: Eingabesteuerelemente & JavaScript-Interoperabilität

Im ersten Teil des Tutorials wurden nur Daten ausgegeben, nun bekommt die Webanwendung zusätzlich Eingabesteuerelemente.

In Pocket speichern vorlesen Druckansicht 16 Kommentare lesen
Lesezeit: 13 Min.
Von
  • Dr. Holger Schwichtenberg
Inhaltsverzeichnis

Der erste Teil des Tutorials zum Erstellen der Aufgabenverwaltung "MiracleList" als Blazor-WebAssembly-Anwendung endete mit der Darstellung der Kategorienliste (links in Abb. 1) und der Anzeige der Aufgaben in einer Kategorie (Mitte in Abb. 1), die das Cloud-basierte Backend per WebAPI-Aufruf geladen hatte.

MiracleList mit Blazor WebAssembly (Abb. 1)
Blazor-Tutorial

Als Erstes werden in diesem Teil die Texteingabesteuerelemente new Category … und new Task… ergänzt, die in Abbildung 1 jeweils oberhalb der ersten und zweiten Spalte zu sehen sind. Im Listing Index.razor aus dem ersten Artikel des Tutorials gab es dazu zwei Platzhalter "@*TODO*@". Diese werden nun durch <input>-Tags ersetzt:

<input name="newCategoryName" type="text" class="form-control" @bind="newCategoryName" @onkeyup="(e) => NewCategory_Keyup(e)" placeholder="new Category..." />

und

<input name="newTaskTitle" type="text" class="form-control" disabled="@(this.category == null)" @bind="newTaskTitle" @onkeyup="(e) => NewTask_Keyup(e)" placeholder="new Task..." />

Beide Steuerelemente haben das gleiche Verhalten: @bind definiert eine Zwei-Wege-Datenbindung an eine Property im C#-Programmcode, und durch Festlegen einer Ereignisbehandlung für @onkeyup lässt sich bei jedem Tastaturanschlag eine Ereignisbehandlungsroutine aufrufen. Die Eingabemöglichkeit für neue Aufgaben ist zudem deaktiviert (disabled), wenn aktuell keine Kategorie gewählt ist.

Damit das Szenario kompiliert, ist auch die Code-Behind-Datei (Index.razor.cs) anzupassen. Hier braucht man einerseits zwei Zeichenketten-Properties

string newCategoryName { get; set; }
string newTaskTitle { get; set; }

und andererseits die passenden Ereignisbehandlungen (s. Listing 1). Dort erkennt man den Sinn der Ereignisbehandlung mit @onkeyup: Das Drücken der Enter-Taste soll die Aktion auslösen.

using Microsoft.AspNetCore.Components.Web;
…
/// <summary>
  /// Use Keyup instead of Keypress as the actual data binding did not yet happen when Keypress is fired
  /// </summary>
  public async Task NewCategory_Keyup(KeyboardEventArgs e)
  {
   if (e.Key == "Enter")
   {
    if (!String.IsNullOrEmpty(this.newCategoryName))
    {
     var newcategory = await proxy.CreateCategoryAsync(newCategoryName, am.Token);
     await ShowCategorySet();
     await ShowTaskSet(newcategory);
    }
   }
  }

  /// <summary>
  /// Use Keyup instead of Keypress as the actual data binding did not yet happen when Keypress is fired
  /// </summary>
  public async Task NewTask_Keyup(KeyboardEventArgs e)
  {
   if (e.Key == "Enter")
   {
    if (!String.IsNullOrEmpty(this.newTaskTitle))
    {
     if (string.IsNullOrEmpty(newTaskTitle)) return;
     var t = new BO.Task();
     t.TaskID = 0; // notwendig für Server, da der die ID vergibt
     t.Title = newTaskTitle;
     t.CategoryID = this.category.CategoryID;
     t.Importance = BO.Importance.B;
     t.Created = DateTime.Now;
     t.Due = null;
     t.Order = 0;
     t.Note = "";
     t.Done = false;
     await proxy.CreateTaskAsync(t, am.Token);
     await ShowTaskSet(this.category);
     this.newTaskTitle = "";
    }
   }
  }

Listing 1: Ereignisbehandlung

Beim Anlegen einer Kategorie ruft man auf dem Server die Operation /CreateCategory via Wrapper-Methode CreateCategoryAsync() auf. Dabei sind lediglich der Name der neuen Kategorie und das Token zu übergeben, das durch die /Login-Operation im ersten Teil des Tutorials gewonnen wurde. Anhand des Tokens weiß das Backend, welche Benutzer hier eine neue Aufgabenkategorie anlegen. Bei der Operation /CreateTask ist hingegen ein komplettes Task-Objekt zu übergeben; der Client kann hier Einfluss auf alle Einstellungen nehmen. Nach dem Ausführen der beiden Operationen aktualisiert man die Ansicht durch das Neuladen der Liste der Kategorien und Aufgaben.

Den Status einer Aufgabe können Nutzer des MiracleList-Frontends über das große Kontrollkästchen steuern. Im ersten Teil des Tutorials war dort folgender Markup-Code hinterlegt:

<input type="checkbox" name="@("done" + t.TaskID)" id="@("done" + t.TaskID)" checked="@t.Done" class="MLcheckbox" />

Nun wird das Beispiel um eine Ereignisbehandlung für @onchange erweitert. Exemplarisch zeigt das, dass sich schon im Markup zur Ereignisbehandlung eine komplexe Befehlsfolge als sogenanntes Statement Lambda => { … } angeben lässt:

<input type="checkbox" name="@("done" + t.TaskID)" id="@("done" + t.TaskID)" checked="@t.Done" @onchange=@(async(eventArgs) => { t.Done = (bool)eventArgs.Value;  await proxy.ChangeTaskAsync(t, am.Token);  }) />

Zuerst gilt es, die Boolean-Property Done umzukehren und dann die WebAPI-Operation /ChangeTask über die generierte Wrapper-Methode ChangeTaskAsync() asynchron aufzurufen. Spannend ist, dass das Template hier sowohl auf die Proxy-Instanz (proxy) als auch auf die Instanz des Authentication Manager (am) aus der Code-Behind-Datei zugreifen kann. Das ist möglich, weil Build-Werkzeuge in Visual Studio aus dem Markup-Code auch eine Klasse erzeugen, die sie mit der Klasse in der Code-Behind-Datei vereinen – für Entwickler wahlweise als partielle Klasse oder per Vererbung.

Diesen Inline-Programmierstil werden einige Entwickler schätzen, da sie auf den ersten Blick sehen, was passiert. Andere Entwickler, einschließlich des Autors, halten das für eher unübersichtlich und bevorzugen eine dedizierte Ereignisbehandlungsroutine.