Blog

.NET 7.0 bringt Desktop-Features zu .NET MAUI

Die Eroberung des Desktops

Apr 21, 2023

.NET MAUI bringt in .NET 7.0 einige spannende Neuerungen, die vor allem die Herzen von Desktopentwickler:innen höherschlagen lassen. Das ist vor allem wegen des knappen Zeithorizonts eine angenehme Überraschung, denn gerade einmal fünfeinhalb Monate lagen zwischen der verspäteten Erstveröffentlichung von .NET MAUI am 23. Mai 2022 und dem ersten großen Update zur .NET Conf 2022 am 7. November 2022. Microsofts Cross-Plattform-Team hatte also weniger als halb so viel Zeit wie andere .NET-Produktteams.

Als Microsoft .NET MAUI erstmals ankündigte, wurde das Cross-Plattform-Framework als „Evolution von Xamarin.Forms, von mobilen erweitert auf Desktop-Szenarien“ vorgestellt.

SIE LIEBEN UI?

Entdecken Sie die BASTA! Tracks

Auch wenn es die versprochene Erweiterung mit .NET 6 schon gab – schließlich lief MAUI bereits unter Windows und macOS –, wirkte die Desktopumsetzung an einigen Stellen noch unfertig. Umso erfreulicher ist es, dass der Fokus der neuen Funktionen von .NET MAUI klar im Desktopbereich liegt.

Fensterbauer

Das Öffnen mehrerer Anwendungsfenster ist aus der Desktopentwicklung seit über 30 Jahren nicht mehr wegzudenken. Unter .NET MAUI und dem Vorgänger Xamarin.Forms war es aufgrund der ursprünglichen Fokussierung auf mobile Betriebssysteme jedoch nicht ohne weiteres möglich. Mit .NET 7 gibt es nun den in Listing 1 gezeigten plattformübergreifenden Weg zum Öffnen neuer Fenster über die Methode OpenWindow des Application-Objekts.

Listing 1

private void OpenDetailsPageInNewWindow(Session session)
{
  var detailsVM = new SessionDetailPageViewModel
  {
    Session = session
  };
  var sessionPage = new SessionDetailPage(detailsVM);
  var window = new Window(sessionPage);
 
  Application.Current.OpenWindow(window);
}

Die neue Funktionalität, die Sie in Abbildung 1 im Einsatz sehen, kann unter Android, macOS und iPadOS (also iOS auf dem iPad) genutzt werden. Auf dem iPhone können keine weiteren Fenster geöffnet werden.

Abb. 1: .NET MAUI ermöglicht unter .NET 7 das Öffnen mehrerer Anwendungsfenster

Das Öffnen neuer Fenster ist nicht die einzige Verbesserung im Fensterumfeld, die .NET MAUI unter .NET 7 mitbringt. Unter Windows können außerdem Fenstergröße und Fensterposition konfiguriert werden, wie Listing 2 zeigt. Der abgebildete Quellcode läuft so jedoch nur unter Windows. Unter macOS gibt es zumindest einen Workaround, über den die Fenstergröße gesetzt werden kann, unter Android und iOS ist es gar nicht möglich. Eine detaillierte Anleitung zum Workaround finden Sie unter [1].

Listing 2

protected override Window CreateWindow(IActivationState activationState)
{
  var window = base.CreateWindow(activationState);
 
  // Fensterposition setzen
  window.X = 300;
  window.Y = 100;
 
  // Größe des Fensters definieren
  window.Width = 700;
  window.Height = 800;
  return window;
}

ZUM NEWSLETTER

Regelmäßig News zur Konferenz und der .NET-Community

Menüs und ToolTipps

Bereits unter Xamarin.Forms gab es das SwipeView-Element, mit dem über eine horizontale Wischgeste ein seitliches Kontextmenü, ähnlich wie man es von E-Mail- oder Messenger-Apps auf dem Mobiltelefon kennt, öffnen kann. Dieses Feature gibt es auch unter .NET MAUI, nur ist es leider für die meisten Desktopnutzer:innen unbenutzbar. Denn eine Wischgeste zum Öffnen eines Menüs ist unter Desktopbetriebssystemen im Unterschied zu Mobilgeräten unüblich und dürfte daher von den meisten Benutzer:innen übersehen werden. Außerdem lässt sich diese Geste nicht mit der Maus durchführen, sondern nur auf einem Windows-Gerät mit Touchscreen.

Microsoft löst das Problem mit den in Abbildung 1 gezeigten neuen Kontextmenüs. Sie lassen sich unter Windows und macOS wie gewohnt über einen Klick auf die sekundäre Maustaste öffnen. Unter Android und iOS stehen sie nicht zur Verfügung. Wie Listing 3 zeigt, werden Kontextmenüeinträge durch MenuFlyoutItem-Elemente umgesetzt, die über einen Text, ein Command oder einen Click Event Handler sowie ein Icon verfügen können. Icons werden jedoch nur unter Windows, nicht aber unter macOS unterstützt. Neben MenuFlyoutItem-Elementen gibt es noch den MenuFlyoutSeperator zur Anzeige einer Trennlinie und das MenuFlyoutSubItem-Element zur Definition von Untermenüs.

Die neuen ToolTips sind übrigens ein eleganter Weg, die Benutzer:innen dezent darauf hinzuweisen, dass ein Kontextmenü geöffnet werden kann. Genau wie Kontextmenüs, die Sie auch in Listing 3 sehen, können ToolTips zu jedem Bildschirmelement hinzugefügt werden.

Listing 3

<Grid RowDefinitions="25, auto" 
  ToolTipProperties.Text="Kontextmenü über Rechtsklick öffnen">
  <Label Text="{Binding Time}" />
  <Label Text="{Binding Title}" Grid.Row="1" FontSize="Subtitle" FontAttributes="Bold"/>
  <FlyoutBase.ContextFlyout>
    <MenuFlyout>
      <MenuFlyoutItem Text="Favorit" Command="{Binding FavoriteCommand }" />
        <MenuFlyoutItem Text="In neuem Fenster öffnen" Command="{Binding OpenNewWindowCommand }" >
        <MenuFlyoutItem.IconImageSource>
          <FontImageSource FontFamily="FA-6-Solid-900" Glyph="{x:StaticResource IconUpRightFromSquare}" Color="{AppThemeBinding Light=Black, Dark=White}" />
        </MenuFlyoutItem.IconImageSource>
      </MenuFlyoutItem>
      <MenuFlyoutSeparator/>
      <MenuFlyoutSubItem Text="Sprecher anrufen">
        <MenuFlyoutItem Text="Geschäftlich" Command="{Binding CallSpeakerBusinessCommand }"/>
        <MenuFlyoutItem Text="Privat" Command="{Binding CallSpeakerPrivateCommand }" />
      </MenuFlyoutSubItem>
    </MenuFlyout>
  </FlyoutBase.ContextFlyout>
</Grid>

Mausinteraktionen

Auf mobilen Geräten wird primär der Finger zur Interaktion mit Apps genutzt. Neben Tipp- sind Wischgesten die häufigsten Aktionen, die man hier ausführt. Maus-Events wie MouseOverMouseEnter oder MouseMove konnten bisher unter .NET MAUI genau wie zuvor unter Xamarin.Forms aufgrund der Fokussierung auf Fingereingaben auf Mobilgeräten nicht behandelt werden.

Unter .NET 7 können Entwickler:innen nun auch die folgenden Mausgesten behandeln:

  • PointerEntered: Die Maus wird erstmalig über einem Element positioniert.

  • PointerMoved: Die Maus wird über einem Element bewegt.

  • PointerExited: Die Maus verlässt ein Element.

Zusätzlich zu den drei Gesten kann nun auch der sekundäre bzw. Rechtsklick behandelt werden. Listing 4 zeigt die Registrierung der entsprechenden Event Handler im XAML-Code, Listing 5 eine beispielhafte Behandlung in C#. Im gezeigten Beispiel wird die Farbe eines Rechtecks über eine Farbanimation verändert, sobald Benutzer:innen die Maus über das Rechteck bewegen oder sie wieder hinausbewegen.

Listing 4

<Rectangle BackgroundColor="{StaticResource Primary}"
  WidthRequest="300" 
  HeightRequest="200"
  HorizontalOptions="Center"
  VerticalOptions="Center"
  ToolTipProperties.Text="Hover und Klick">
  <Rectangle.GestureRecognizers>
    <TapGestureRecognizer Buttons="Primary" Tapped="PrimaryTapped" />
    <TapGestureRecognizer Buttons="Secondary" Tapped="SecondaryTapped" />
    <PointerGestureRecognizer 
       PointerEntered="OnPointerEntered"
       PointerExited="OnPointerExited"
       PointerMoved="OnPointerMoved" />
    </Rectangle.GestureRecognizers>
</Rectangle>
<Label x:Name="PositionLabel" Text="Pos:"/>

Listing 5

private async void SecondaryTapped(object sender, TappedEventArgs e)
{
  await DisplayAlert("Click", "Secondary", "OK");
}
 
private async void OnPointerEntered(object sender, PointerEventArgs e)
{
  var rectangle = sender as Rectangle;
  await rectangle.BackgroundColorTo(Colors.Red);
}
 
private async void OnPointerExited(object sender, PointerEventArgs e)
{
  var rectangle = sender as Rectangle;
  await rectangle.BackgroundColorTo(Color.FromArgb("#512BD4"));
}
 
private void OnPointerMoved(object sender, PointerEventArgs e)
{
  Point? windowPosition = e.GetPosition(null);
  PositionLabel.Text = 
    $"Position: x: {windowPosition.Value.X} -  y: {windowPosition.Value.Y}";
}

Wer die Änderung der Optik eines Steuerelements, sobald die Maus darüber bewegt wird, lieber deklarativ durchführt, kann dazu den neuen PointerOver VisualState des VisualStateManager nutzen. In Listing 6 sehen Sie, wie es geht. Im gezeigten Beispiel wird die Hintergrundfarbe eines Buttons auf Rot geändert, sobald die Maus über den Button bewegt wird. Eine ausführliche Dokumentation zu Visual States unter .NET MAUI gibt es unter [2].

 

Listing 6

<Button Text="Beweg die Maus über mich!">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="CommonStates">
      <VisualState x:Name="Normal">
        <VisualState.Setters>
          <Setter Property="BackgroundColor" Value="Blue" />
        </VisualState.Setters>
      </VisualState>
 
      <VisualState x:Name="PointerOver">
        <VisualState.Setters>
          <Setter Property="BackgroundColor" Value="Red" />
        </VisualState.Setters>
      </VisualState>
    </VisualStateGroup>
  </VisualStateManager.VisualStateGroups>
</Button>

Karten

Alle bisher in diesem Artikel vorgestellten neuen Funktionen bezogen sich auf die Entwicklung von Desktop-Apps mit .NET MAUI. Die letzte neue Funktion, die Darstellung von Karten, wird unter macOS, Android und iOS unterstützt. Unter Windows wirft die Kartenkomponente einen Laufzeitfehler, da das zugrunde liegende UI-Framework WinUI 3 keine Kartenkomponente besitzt. Auf den drei anderen Betriebssystemen wird jeweils das native Kartensteuerelement des Betriebssystems genutzt. Abbildung 2 zeigt zum Beispiel die Nutzung von Google Maps unter Android.

Mit dem Map-Element können Sie im Code auf verschiedene Weise interagieren. Listing 7 zeigt, wie Sie den gezeigten Kartenausschnitt deklarativ über die Eigenschaft MapSpan festlegen können. In Listing 8 sehen Sie, wie Sie per C#-Quellcode einen Pin zur Karte hinzufügen können.

Listing 7

<maps:Map x:Name="map">
  <x:Arguments>
    <MapSpan>
      <x:Arguments>
        <sensors:Location>
          <x:Arguments>
            <x:Double>50.5014483</x:Double>
            <x:Double>7.308297599999</x:Double>
          </x:Arguments>
        </sensors:Location>
        <x:Double>0.01</x:Double>
        <x:Double>0.01</x:Double>
      </x:Arguments>
    </MapSpan>
</x:Arguments>
Listing 8
Pin qualityBytesPin = new Pin
{
  Location = new Location(50.5014483, 7.308297599999),
  Label = "Quality Bytes GmbH",
  Address = "Bad Breisig",
  Type = PinType.Place
};
 
map.Pins.Add(qualityBytesPin);

Zusätzlich zu den beiden gezeigten Funktionen können Sie außerdem Formen wie Kreise, Linien oder Polygone auf die Karte zeichnen oder die Darstellung über die Eigenschaft MapType der Karte auf eine Straßen-, Satelliten-, oder Hybridansicht festlegen.

Abb. 2: Karten können unter Android, iOS und macOS dargestellt werden

Performance und Stabilität

Zusätzlich zur Umsetzung neuer Funktionen setzte sich das .NET-MAUI-Team intensiv mit dem Thema Performance auseinander. Unter [3] beschreibt Microsoft, welche Verbesserungen unter der Haube vorgenommen wurden, um die Performance zu optimieren. Im Fokus standen bei der Optimierung die allgemeine Rendering-Geschwindigkeit sowie das Scroll-Verhalten in Listen.

Über die Performance hinaus arbeitete Microsoft auch an der Stabilität. Im Bereich Visual-Studio-Integration konnten 80 Prozent der Bugs von Visual Studio 2022 17.3 und .NET MAUI 6 unter Visual Studio 2022 17.4 und .NET MAUI 7 behoben werden. Außerdem wurde eine beträchtliche Anzahl an GitHub-Issues geschlossen.

Dass das Team hier jedoch noch einen weiten Weg vor sich hat, zeigen die knapp 2 000 offenen Issues. Der Fairness halber muss allerdings erwähnt werden, dass nicht alle Issues Fehler sind, sondern auch Feature-Requests sowie Duplikate.

Fazit

Die Anzahl der neuen .NET-MAUI-Funktionen mag auf den ersten Blick enttäuschen, schließlich lassen sie sich an zwei Händen abzählen. Zieht man jedoch in Betracht, dass das Team nur fünfeinhalb Monate Zeit hatte und darüber hinaus an Performance und Stabilität gearbeitet hat, sieht es gar nicht mehr so schlecht aus.

Die neuen Funktionen haben sicherlich einen geringen Wow-Faktor, schließen aber wichtige Funktionslücken und machen .NET MAUI somit immer mehr zu einer validen Alternative für die Entwicklung plattformübergreifender Desktopanwendungen.

Links & Literatur

[1] https://learn.microsoft.com/de-de/dotnet/maui/fundamentals/windows?view=net-maui-7.0#position-and-size-a-window

[2] https://learn.microsoft.com/de-de/dotnet/maui/user-interface/visual-states?view=net-maui-7.0

[3] https://devblogs.microsoft.com/dotnet/dotnet-7-performance-improvements-in-dotnet-maui/

 

Ihr aktueller Zugang zur .NET- und Microsoft-Welt.
Der BASTA! Newsletter:

Behind the Tracks

.NET Framework & C#
Visual Studio, .NET, Git, C# & mehr

Agile & DevOps
Agile Methoden, wie Scrum oder Kanban und Tools wie Visual Studio, Azure DevOps usw.

Web Development
Alle Wege führen ins Web

Data Access & Storage
Alles rund um´s Thema Data

JavaScript
Leichtegewichtig entwickeln

UI Technology
Alles rund um UI- und UX-Aspekte

Microservices & APIs
Services, die sich über APIs via REST und JavaScript nutzen lassen

Security
Tools und Methoden für sicherere Applikationen

Cloud & Azure
Cloud-basierte & Native Apps