Übersicht über WPF-Fenster (WPF .NET)

Benutzer interagieren mit Windows Presentation Foundation (WPF)-Anwendungen über Fenster. Die Hauptaufgabe eines Fensters besteht darin, Inhalt zu hosten, der Daten visuell darstellen kann und Benutzern die Interaktion mit Daten ermöglicht. WPF-Anwendungen stellen ihre eigenen Fenster mithilfe der -Klasse Window zur Verfügung. In diesem Artikel wird Window vorgestellt, ehe die Grundlagen zum Erstellen und Verwalten von Fenstern in Anwendungen behandelt werden.

Wichtig

In diesem Artikel wird XAML verwendet, das aus einem C#-Projekt generiert wurde. Wenn Sie Visual Basic verwenden, sieht der XAML-Code möglicherweise etwas anders aus. Diese Unterschiede sind in der Regel bei x:Class Attributwerten vorhanden. C# enthält den Stammnamespace für das Projekt, Visual Basic nicht.

Die Projektvorlagen für C# erstellen einen App Typ, der in der app.xaml Datei enthalten ist. In Visual Basic wird der Typ Application und die Datei Application.xaml benannt.

Die Fensterklasse

In WPF wird ein Fenster von der Window Klasse gekapselt, die Sie für folgende Aufgaben verwenden:

  • Anzeigen eines Fensters
  • Konfigurieren der Größe, Position und Darstellung eines Fensters
  • Hosten von anwendungsspezifischem Inhalt
  • Verwalten der Lebensdauer eines Fensters

In der folgenden Abbildung werden die Bestandteile eines Fensters dargestellt:

Screenshot that shows parts of a WPF window.

Ein Fenster wird in zwei Bereiche geteilt: der Nicht-Clientbereich und der Clientbereich.

Der Nicht-Clientbereich eines Fensters wird mit WPF implementiert und enthält die Teile eines Fenster, die den meisten Fenstern gemeinsam sind, einschließlich:

  • Titelleiste (1-5).
  • Symbol (1).
  • Titel (2).
  • Schaltflächen Minimieren (3), Maximieren (4) und Schließen (5).
  • Systemmenü (6) mit Menüelementen. Wird angezeigt, wenn auf das Symbol (1) geklickt wird.
  • Randbereich (7).

Der Clientbereich eines Fensters befindet sich im Nicht-Clientbereich eines Fensters und wird von Entwicklern dazu verwendet, anwendungsspezifischen Inhalt hinzuzufügen, z. B. Menüleisten, Symbolleisten und Steuerelemente.

  • Clientbereich (8).
  • Klammergröße ändern (9). Dies ist ein Steuerelement, das dem Clientbereich (8) hinzugefügt wurde.

Implementieren eines Fensters

Die Implementierung eines typischen Fensters umfasst die Darstellung und das Verhalten. Dabei definiert die Darstellung, wie ein Fenster einem Benutzer angezeigt wird und das Verhalten die Funktionsweise eines Fensters bei der Interaktion mit Benutzern. In WPF können Sie die Darstellung und das Verhalten eines Fensters entweder mit Code oder mit XAML-Markup implementieren.

Im Allgemeinen wird die Darstellung eines Fenster jedoch mit XAML-Markup und dessen Verhalten mit Code-Behind implementiert, wie im folgenden Beispiel gezeigt.

<Window x:Class="WindowsOverview.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WindowsOverview"
        >

    <!-- Client area containing the content of the window -->
    
</Window>

Der folgende Code ist der CodeBehind für den XAML.

using System.Windows;

namespace WindowsOverview
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }
}
Public Class Window1

End Class

Folgende Voraussetzungen müssen erfüllt sein, damit die XAML-Markupdatei und die Code-Behind-Datei zusammenarbeiten:

  • Im Markup muss das Window-Element das x:Class-Attribut enthalten. Beim Erstellen der Anwendung führt das Vorhandensein vonx:Class-Attribut die Microsoft-Build-Engine dazu, dass eine partial-Klasse erstellt wird, die von Window abgeleitet wird und den durch das x:Class-Attribut festgelegten Namen erhält. Dies erfordert das Hinzufügen einer XML-Namespacedeklaration für das XAML-Schema (xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"). Die generierte partial-Klasse implementiert die InitializeComponent-Methode, die zum Registrieren der Ereignisse und Festlegen der Eigenschaften aufgerufen wird, die im Markup implementiert werden.

  • Bei Code-Behind muss die Klasse eine partial-Klasse mit demselben Namen sein, der im Markup durch das x:Classs-Attribut angegeben ist, und sie muss von Window abgeleitet werden. Auf diese Weise kann die CodeBehind-Datei mit der partial-Klasse verknüpft werden, die beim Erstellen der Anwendung für weitere Informationen siehe Erstellen einer WPF-Anwendung für die Markupdatei generiert wird.

  • Bei Code-Behind muss die Window-Klasse einen Konstruktor implementieren, der die InitializeComponent-Methode aufruft. InitializeComponent wird durch die generierte partial-Klasse der Markupdatei implementiert, um Ereignisse zu registrieren und im Markup definierte Eigenschaften festzulegen.

Hinweis

Wenn Sie Ihrem Projekt ein neues Window mithilfe von Visual Studio hinzufügen, wird Window unter Verwendung von Markup und Code-Behind implementiert. Außerdem wird eine Konfiguration eingefügt, die zum Erstellen der Verknüpfung zwischen Markup- und Code-Behind-Dateien, wie hier beschrieben, benötigt wird.

Mit dieser Konfiguration können Sie den Fokus auf das Definieren der Fensterdarstellung in XAML-Markup richten und das Fensterverhalten in Code-Behind implementieren. Das nachfolgende Beispiel zeigt ein Fenster mit einer Schaltfläche, die einen Ereignishandler für das Click-Ereignis definiert. Dies wird im XAML-Code implementiert, und der Handler wird im CodeBehind implementiert.

<Window x:Class="WindowsOverview.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WindowsOverview"
        >

    <!-- Client area containing the content of the window -->

    <Button Click="Button_Click">Click This Button</Button>
    
</Window>

Der folgende Code ist der CodeBehind für den XAML.

using System.Windows;

namespace WindowsOverview
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Button was clicked.");
        }
    }
}
Public Class Window1

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        MessageBox.Show("Button was clicked.")
    End Sub

End Class

Konfigurieren eines Fensters für MSBuild

Die Implementierung des Fensters bestimmt dessen Konfiguration für MSBuild. Für ein Fenster, das sowohl mit XAML-Markup als auch mit Code-Behind definiert ist:

  • XAML-Markupdateien werden als MSBuild Page-Elemente konfiguriert.
  • Code-Behind-Dateien werden als MSBuild Compile-Elemente konfiguriert.

.NET SDK-Projekte importieren automatisch die richtigen Page und Compile-Elemente für Sie, und Sie müssen diese nicht deklarieren. Wenn das Projekt für WPF konfiguriert ist, werden die XAML-Markupdateien automatisch als Page Elemente importiert, und die entsprechende CodeBehind-Datei wird als Compile importiert.

MSBuild-Projekte importieren die Typen nicht automatisch, und Sie müssen sie selbst deklarieren:

<Project>
    ...
    <Page Include="MarkupAndCodeBehindWindow.xaml" />
    <Compile Include=" MarkupAndCodeBehindWindow.xaml.cs" />
    ...
</Project>

Weitere Informationen zum Erstellen von WPF-Anwendungen finden Sie unter Erstellen einer WPF-Anwendung.

Fensterlebensdauer

Wie alle Klassen hat auch ein Fenster eine Lebensdauer, die mit dem erstmaligen Instanziieren beginnt. Anschließend wird es geöffnet, aktiviert/deaktiviert und schließlich geschlossen.

Öffnen eines Fensters

Wenn Sie ein Fenster öffnen möchten, müssen Sie zuerst eine Instanz davon erstellen. Dies wird im folgenden Beispiel veranschaulicht:

using System.Windows;

namespace WindowsOverview
{
    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // Create the window
            Window1 window = new Window1();

            // Open the window
            window.Show();
        }
    }
}
Class Application

    Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
        ' Create the window
        Dim window As New Window1

        ' Open the window
        window.Show()
    End Sub

End Class

In diesem Beispiel wird Window1 beim Starten der Anwendung instanziiert, was beim Auslösen des Startup-Ereignisses erfolgt. Weitere Informationen zum Startfenster finden Sie unter So erhalten oder setzen Sie das Hauptanwendungsfenster.

Wird ein Fenster instanziiert, wird ein Verweis darauf automatisch zu einer -Liste von Fenstern hinzugefügt, die vom Application-Objekt verwaltet wird. Das erste zu instanziierte Fenster wird automatisch von Application als Hauptanwendungsfensterfestgelegt.

Das Fenster wird schließlich durch den Aufruf der Show-Methode geöffnet, wie im folgenden Bild gezeigt:

WPF Window with a single button inside.

Ein Fenster, das durch Aufrufen von Show geöffnet wird, ist ein modusloses Fenster, und die Anwendung verhindert nicht, dass Benutzer mit anderen Fenstern in der Anwendung interagieren. Das Öffnen eines Fensters mit ShowDialog öffnet ein Fenster als modal und schränkt die Benutzerinteraktion auf das jeweilige Fenster ein. Weitere Informationen finden Sie unter Übersicht über Dialogfelder.

Wenn Show aufgerufen wird, führt ein Fenster die Initialisierung aus, bevor es zum Festlegen der Infrastruktur angezeigt wird, durch die es Benutzereingaben empfangen kann. Wenn das Fenster initialisiert wird, wird das SourceInitialized-Ereignis hervorgerufen und das Fenster wird angezeigt.

Weitere Informationen finden Sie unter Öffnen eines Fensters oder Dialogfelds.

Startfenster

Im vorherigen Beispiel wurde das Startup -Ereignis verwendet, um Code auszuführen, der das erste Anwendungsfenster anzeigte. Als Verknüpfung können Sie stattdessen StartupUri verwenden, um den Pfad zu einer XAML-Datei in Ihrer Anwendung anzugeben. Die Anwendung erstellt automatisch das von dieser Eigenschaft angegebene Fenster und zeigt es an.

<Application x:Class="WindowsOverview.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WindowsOverview"
             StartupUri="ClippedWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Besitz von Fenstern

Ein Fenster, das mithilfe der Show-Methode geöffnet wird, hat keine implizite Beziehung zu dem Fenster, in dem es erstellt wurde. Benutzer können unabhängig vom anderen Fenster mit beiden Fenstern interagieren. Dies bedeutet, dass beide Fenster Folgendes tun können:

  • Decken Sie das andere (es sei denn, die Topmost-Eigenschaft eines der Fenster ist auf true eingestellt).
  • Es wird minimiert, maximiert und wiederhergestellt, ohne das andere zu beeinflussen.

Bei einigen Fenstern ist eine Beziehung zu dem Fenster erforderlich, durch das es geöffnet wird. Eine integrierte Entwicklungsumgebung (IDE)-Anwendung kann beispielsweise Eigenschaftenfenster und Toolfenster öffnen, deren typisches Verhalten es ist, das Fenster zu überdecken, von dem es erstellt wurde. Darüber hinaus sollten solche Fenster stets mit den Fenstern geschlossen, minimiert, maximiert und wiederhergestellt werden, durch die sie erstellt wurden. Eine solche Beziehung lässt sich herstellen, indem festgelegt wird, dass ein Fenster das andere besitzt. Dazu legen Sie dieOwner-Eigenschaft von zum Besitzer gehöriges Fenster mit einem Verweis auf Besitzerfenster fest. Dies wird im folgenden Beispiel gezeigt.

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Create a window and make the current window its owner
    var ownedWindow = new ChildWindow1();
    ownedWindow.Owner = this;
    ownedWindow.Show();
}
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    ' Create a window and make the current window its owner
    Dim ownedWindow As New ChildWindow1
    ownedWindow.Owner = Me
    ownedWindow.Show()
End Sub

Nach Einrichten des Besitzes:

  • Das zum Besitzer gehörige Fenster kann auf sein Besitzerfenster verweisen, indem der Wert der Owner-Eigenschaft überprüft wird.
  • Das Besitzerfenster kann alle ihm gehörenden Fenster durch Überprüfen des Wertes der OwnedWindows-Eigenschaft ermitteln.

Aktivieren von Fenstern

Wenn ein Fenster zum ersten Mal geöffnet wird, dann wird es das aktive Fenster. Das aktive Fenster ist das Fenster, das gegenwärtig Benutzereingaben annimmt, z. B. Tastenanschläge und Mausklicks. Wenn ein Fenster aktiv wird, löst es das Activated-Ereignis aus.

Hinweis

Beim erstmaligen Öffnen eines Fensters werden die Loaded- und ContentRendered-Ereignisse erst ausgelöst, nachdem das Activated-Ereignis ausgelöst wurde. Vor diesem Hintergrund gilt ein Fenster als tatsächlich geöffnet, nachdem ContentRendered ausgelöst wurde.

Nachdem ein Fenster aktiv geworden ist, kann ein Benutzer ein weiteres Fenster in derselben Anwendung oder eine andere Anwendung aktivieren. In diesem Fall wird das derzeit aktive Fenster deaktiviert, und es löst das Deactivated-Ereignis aus. Wenn der Benutzer ein derzeit deaktiviertes Fenster auswählt, wird das Fenster entsprechend neu aktiviert, und Activated wird ausgelöst.

Ein häufiger Grund für die Handhabung von Activated und Deactivated ist das Aktivieren und Deaktivieren von Funktionen, die nur bei aktivem Fenster ausgeführt werden können. In einigen Fenstern wird beispielsweise interaktiver Inhalt angezeigt, der andauernde Benutzereingaben oder Aufmerksamkeit erfordert, wie beispielsweise Spiele und Videoplayer. Das folgende Beispiel ist ein vereinfachter Videoplayer, der zeigt, wie man Activated und Deactivated behandelt, um dieses Verhalten zu implementieren.

<Window x:Class="WindowsOverview.CustomMediaPlayerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Activated="Window_Activated"
        Deactivated="Window_Deactivated"
        Title="CustomMediaPlayerWindow" Height="450" Width="800">
    <Grid>
        <MediaElement x:Name="mediaElement" Stretch="Fill"
                      LoadedBehavior="Manual" Source="numbers.mp4" />
    </Grid>
</Window>

Der folgende Code ist der CodeBehind für den XAML.

using System;
using System.Windows;

namespace WindowsOverview
{
    public partial class CustomMediaPlayerWindow : Window
    {
        public CustomMediaPlayerWindow() =>
            InitializeComponent();

        private void Window_Activated(object sender, EventArgs e)
        {
            // Continue playing media if window is activated
            mediaElement.Play();
        }

        private void Window_Deactivated(object sender, EventArgs e)
        {
            // Pause playing if media is being played and window is deactivated
            mediaElement.Pause();
        }
    }
}
Public Class CustomMediaPlayerWindow
    Private Sub Window_Activated(sender As Object, e As EventArgs)
        ' Continue playing media if window Is activated
        mediaElement.Play()
    End Sub

    Private Sub Window_Deactivated(sender As Object, e As EventArgs)
        ' Pause playing if media is being played and window is deactivated
        mediaElement.Pause()
    End Sub
End Class

Andere Anwendungstypen führen im Hintergrund möglicherweise weiterhin Code aus, nachdem ein Fenster deaktiviert wurde. Ein E-Mail-Client kann z. B. weiterhin den E-Mail-Server abrufen, während der Benutzer andere Anwendungen verwendet. Während das Hauptfenster deaktiviert ist, stellen derartige Anwendungen häufig zusätzliches oder anderes Verhalten zur Verfügung. Für ein E-Mail-Programm kann das sowohl das Hinzufügen des neuen E-Mail-Elements zum Posteingang als auch eines Benachrichtigungssymbol in die Taskleiste bedeuten. Ein Benachrichtigungssymbol muss nur angezeigt werden, wenn das E-Mail-Fenster nicht aktiv ist. Dies wird durch Überprüfen der IsActive-Eigenschaft bestimmt.

Nach Ausführen einer Hintergrundtask benachrichtigt ein Fenster den Benutzer etwas dringlicher, indem die Activate-Methode aufgerufen wird. Wenn der Benutzer mit einer anderen Anwendung interagiert, die durch Aufrufen von Activate gestartet wird, blinkt die Taskleistenschaltfläche des Fensters. Wenn ein Benutzer jedoch mit der aktuellen Anwendung interagiert, wird durch Aufrufen von Activate das Fenster in den Vordergrund gestellt.

Hinweis

Sie können die Aktivierung des Anwendungsbereichs mit den Application.Activated- und Application.Deactivated-Ereignissen behandeln.

Verhindern der Fensteraktivierung

Es gibt Szenarien, in denen angezeigte Fenster nicht aktiviert werden sollten, z. B. Unterhaltungsfenster einer Chat-Anwendung oder Benachrichtigungsfenster einer E-Mail-Anwendung.

Falls Ihre Anwendung ein Fenster bereitstellt, das nicht aktiviert werden soll, können Sie dessen ShowActivated-Eigenschaft auf false festelegen, bevor Sie die Show-Methode zum ersten Mal ausführen. Daraus folgt:

  • Das Fenster ist nicht aktiviert.
  • Das Activated-Ereignis des Fensters wird nicht ausgelöst.
  • Das momentan aktivierte Fenster bleibt aktiviert.

Das Fenster wird jedoch aktiviert, sobald der Benutzer es durch Klicken auf den Client- oder Nicht-Clientbereich aktiviert. In diesem Fall:

  • Das Fenster wird aktiviert.
  • Das Activated-Ereignis des Fensters wird nicht ausgelöst.
  • Das zuvor aktivierte Fenster wird deaktiviert.
  • Die Deactivated- und Activated-Ereignisse des Fensters werden dann wie erwartet als Reaktion auf Anwenderaktionen ausgelöst.

Schließen eines Fensters

Die Lebensdauer eines Fensters endet, wenn der Benutzer das Fenster schließt. Sobald ein Fenster geschlossen wurde, kann es nicht erneut geöffnet werden. Ein Fenster kann mithilfe der Elemente im Nicht-Clientbereich geschlossen werden, z. B. mit den folgenden:

  • Das Element Schließen im Menü System.
  • Drücken von ALT+F4.
  • Klicken auf die Schaltfläche Schließen.
  • Drücken Sie ESC, wenn für eine Schaltfläche die IsCancel-Eigenschaft in einem true modalen Fenster auf festgelegt ist.

Zum Schließen eines Fensters können Sie dem Clientbereich weitere Mechanismen hinzufügen. Zu den gebräuchlichsten zählen:

  • Das Element Beenden im Menü Datei, i. d. R. für Hauptanwendungsfenster.
  • Das Element Schließen im Menü Datei, i. d. R. in einem sekundären Anwendungsfenster.
  • Das Element Abbrechen, i. d. R. in einem modalen Dialogfeld.
  • Das Element Schließen, i. d. R. in einem nicht modalen Dialogfeld.

Sie müssen die Close-Methode aufrufen, um ein Fenster mit einem der benutzerdefinierten Mechanismen zu schließen. Im folgenden Beispiel wird die Fähigkeit implementiert, ein Fenster mithilfe von Beenden im Menü Datei zu schließen.

<Window x:Class="WindowsOverview.ClosingWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ClosingWindow" Height="450" Width="800">
    <StackPanel>
        <Menu>
            <MenuItem Header="_File">
                <MenuItem Header="E_xit" Click="fileExitMenuItem_Click" />
            </MenuItem>
        </Menu>
    </StackPanel>
</Window>

Der folgende Code ist der CodeBehind für den XAML.

using System.Windows;

namespace WindowsOverview
{
    public partial class ClosingWindow : Window
    {
        public ClosingWindow() =>
            InitializeComponent();

        private void fileExitMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Close the current window
            this.Close();
        }
    }
}
Public Class ClosingWindow
    Private Sub fileExitMenuItem_Click(sender As Object, e As RoutedEventArgs)
        ' Close the current window
        Me.Close()
    End Sub
End Class

Hinweis

Eine Anwendung kann so konfiguriert werden, dass sie automatisch beendet wird, wenn entweder das Hauptanwendungsfenster (siehe MainWindow) oder das letzte Fenster geschlossen wird. Weitere Informationen finden Sie unter ShutdownMode.

Während ein Fenster über die im Nicht-Clientbereich und im Clientbereich bereitgestellten Mechanismen explizit geschlossen werden kann, ist es auch möglich, dass es infolge des Verhaltens in anderen Bereichen der Anwendung oder des Fensters implizit geschlossen wird, z. B.:

Wichtig

Ein Fenster kann nicht erneut geöffnet werden, nachdem es geschlossen wurde.

Schließen des Fensters abbrechen

Wenn ein Fenster geschlossen wird, löst es zwei Ereignisse aus: Closing und Closed.

Closing wird ausgelöst, bevor das Fenster geschlossen wird. Zusätzlich werden Mechanismen bereitgestellt, mit deren Hilfe das Schließen des Fensters verhindert werden kann. Der häufigste Grund, um das Schließen eines Fensters zu verhindern, liegt darin, dass Fensterinhalt geänderte Daten enthält. In diesem Fall kann das Closing-Ereignis behandelt werden, um festzustellen, ob Daten geändert wurden und um in diesem Fall den Benutzer zu fragen, ob er mit dem Schließen des Fensters fortfahren oder den Vorgang abbrechen möchte. Das folgende Beispiel zeigt die Schlüsselaspekte der Handhabung von Closing.

<Window x:Class="WindowsOverview.DataWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataWindow" Height="450" Width="800"
        Closing="Window_Closing">
    <Grid>
        <TextBox x:Name="documentTextBox" TextChanged="documentTextBox_TextChanged" />
    </Grid>
</Window>

Der folgende Code ist der CodeBehind für den XAML.

using System.Windows;
using System.Windows.Controls;

namespace WindowsOverview
{
    public partial class DataWindow : Window
    {
        private bool _isDataDirty;

        public DataWindow() =>
            InitializeComponent();

        private void documentTextBox_TextChanged(object sender, TextChangedEventArgs e) =>
            _isDataDirty = true;

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // If data is dirty, prompt user and ask for a response
            if (_isDataDirty)
            {
                var result = MessageBox.Show("Document has changed. Close without saving?",
                                             "Question",
                                             MessageBoxButton.YesNo);

                // User doesn't want to close, cancel closure
                if (result == MessageBoxResult.No)
                    e.Cancel = true;
            }
        }
    }
}
Public Class DataWindow

    Private _isDataDirty As Boolean

    Private Sub documentTextBox_TextChanged(sender As Object, e As TextChangedEventArgs)
        _isDataDirty = True
    End Sub

    Private Sub Window_Closing(sender As Object, e As ComponentModel.CancelEventArgs)

        ' If data is dirty, prompt user and ask for a response
        If _isDataDirty Then
            Dim result = MessageBox.Show("Document has changed. Close without saving?",
                                         "Question",
                                         MessageBoxButton.YesNo)

            ' User doesn't want to close, cancel closure
            If result = MessageBoxResult.No Then
                e.Cancel = True
            End If
        End If

    End Sub
End Class

Dem Closing-Ereignishandler wird ein CancelEventArgs übergeben, der die Cancel-Eigenschaft implementiert, die Sie auf true festlegen, um zu verhindern, dass ein Fenster geschlossen wird.

Wenn Closing nicht behandelt wird oder es behandelt, aber nicht beendet wird, wird das Fenster geschlossen. Kurz bevor ein Fenster tatsächlich geschlossen wird, wird Closed erhoben. An dieser Stelle kann das Schließen des Fensters nicht verhindert werden.

Ereignisse in der Lebensdauer eines Fensters

In der folgenden Darstellung wird die Abfolge der wichtigsten Ereignisse in der Lebensdauer eines Fensters gezeigt:

Diagram that shows events in a window's lifetime.

In der folgenden Abbildung wird die Abfolge der wichtigsten Ereignisse in der Lebensdauer eines Fensters, das ohne Aktivierung angezeigt wird, dargestellt (ShowActivated ist auf false festgelegt, bevor das Fenster angezeigt wird):

Diagram that shows events in a window's lifetime without activation.

Fensterposition

Solange ein Fenster geöffnet ist, befindet sich dessen Position in der x- und y-Dimension relativ zum Desktop. Diese Position kann durch Prüfung der Left- bzw. Top-Eigenschaften ermittelt werden. Legen Sie die Eigenschaften fest, um die Position des Fensters zu ändern.

Sie können auch den Anfangsspeicherort eines Window wenn es zum ersten Mal auftritt, indem Sie die WindowStartupLocation-Eigenschaft mit einer der folgenden WindowStartupLocation-Enumerationwrte einstellen:

Wenn der Startspeicherort als angegeben ist Manual und Left und Top Eigenschaften nicht festgelegt worden sind, fragt das Betriebssystem nach einem Speicherort, in dem Window angezeigt werden soll.

Oberstes Fenster und Z-Reihenfolge

Neben der X- und Y-Position verfügt das Fenster auch über eine Position in der Z-Dimension, die dessen vertikale Position im Verhältnis zu anderen Fenstern bestimmt. Dies wird als Z-Reihenfolge des Fensters bezeichnet. Davon gibt es zwei Typen: die normale Z-Reihenfolge und die oberste Z-Reihenfolge. Die Position eines Fensters in der normalen Z-Reihenfolge hängt davon ab, ob das Fenster derzeit aktiv ist. Standardmäßig befindet sich ein Fenster in der normalen Z-Reihenfolge. Die Position eines Fensters in der obersten Z-Reihenfolge hängt ebenfalls davon ab, ob das Fenster derzeit aktiv ist. Darüber hinaus befinden sich Fenster in der obersten Z-Reihenfolge stets über den Fenstern in der normalen Z-Reihenfolge. Ein Fenster befindet sich in der obersten Z-Reihenfolge, indem seine Topmost-Eigenschaft auf true festgelegt wird.

Innerhalb jedes Z-Reihenfolgen-Typs wird das aktuell aktive Fenster über allen anderen Fenstern derselben Z-Reihenfolge angezeigt.

Fenstergröße

Abgesehen von der Position auf dem Desktop verfügt ein Fenster über eine Größe, die durch mehrere Eigenschaften bestimmt wird, beispielsweise die Eigenschaften für Breite, Höhe und SizeToContent.

MinWidth,Width, und werden MaxWidth verwendet, um den Breitenbereich zu verwalten, den ein Fenster während seiner Lebensdauer haben kann.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    MinWidth="300" Width="400" MaxWidth="500">
</Window>

Die Fensterhöhe wird von MinHeightHeight, und MaxHeightverwaltet.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    MinHeight="300" Height="400" MaxHeight="500">
</Window>

Da die verschiedenen Werte für die Breite und für die Höhe jeweils einen Bereich angeben, kann die Breite und Höhe eines in der Größe veränderbaren Fensters irgendwo innerhalb des angegebenen Bereichs für die entsprechende Dimension liegen. Um seine aktuelle Breite und Höhe zu ermitteln, prüfen Sie jeweilsActualWidth und ActualHeight.

Wenn Sie möchten, dass die Breite und Höhe des Fensters der Größe des Fensterinhalts entspricht, können Sie die SizeToContent-Eigenschaft verwenden, die über folgende Werte verfügt:

Im folgenden Beispiel wird ein Fenster dass die Größe automatisch an seinen Inhalt vertikal und horizontal an, wenn es zuerst angezeigt wird.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    SizeToContent="WidthAndHeight">
</Window>

Im folgenden Beispiel wird gezeigt, wie die SizeToContent-Eigenschaft im Code festlegen, um anzugeben, wie ein Fenster angepasst wird, um seinen Inhalt anzupassen.

// Manually alter window height and width
this.SizeToContent = SizeToContent.Manual;

// Automatically resize width relative to content
this.SizeToContent = SizeToContent.Width;

// Automatically resize height relative to content
this.SizeToContent = SizeToContent.Height;

// Automatically resize height and width relative to content
this.SizeToContent = SizeToContent.WidthAndHeight;
' Manually alter window height and width
Me.SizeToContent = SizeToContent.Manual

' Automatically resize width relative to content
Me.SizeToContent = SizeToContent.Width

' Automatically resize height relative to content
Me.SizeToContent = SizeToContent.Height

' Automatically resize height and width relative to content
Me.SizeToContent = SizeToContent.WidthAndHeight

Rangfolge der Größeneigenschaften

Im Wesentlichen werden die verschiedenen Größeneigenschaften eines Fensters kombiniert, um den Bereich der Breite und der Höhe für ein in der Größe veränderbares Fenster zu definieren. Um sicherzustellen, dass ein gültiger Bereich beibehalten wird, wertet Window die Werte der Größeneigenschaften anhand der folgenden Rangfolgen aus.

Für Höheneigenschaften:

  1. FrameworkElement.MinHeight
  2. FrameworkElement.MaxHeight
  3. SizeToContent.Height / SizeToContent.WidthAndHeight
  4. FrameworkElement.Height

Für Breiteneigenschaften:

  1. FrameworkElement.MinWidth
  2. FrameworkElement.MaxWidth
  3. SizeToContent.Width / SizeToContent.WidthAndHeight
  4. FrameworkElement.Width

Durch die Rangfolge kann beim Maximieren eines Fensters auch dessen Größe festgelegt werden. Dies wird von der WindowState-Eigenschaft verwaltet.

Window state

Während der Lebensdauer eines in der Größe veränderbaren Fenster kann dieses über drei Zustände verfügen: normal, minimiert und maximiert. Ein Fenster mit einem normalen Zustand ist der Standardzustand eines Fensters. Ein Benutzer kann ein Fenster mit diesem Zustand verschieben und dessen Größe ändern, indem er den Ziehpunkt zur Größenänderung oder den Rahmen verwendet, sofern er in der Größe veränderbar ist.

Ein Fenster mit einem minimierten Zustand wird auf seine Taskleistenschaltfläche reduziert, wenn ShowInTaskbar auf true; festgelegt ist. Andernfalls wird es auf die kleinste mögliche Größe reduziert und in der linken unteren Ecke des Desktops angezeigt. Keiner der minimierten Fenstertypen kann mithilfe des Ziehpunkts zur Größenreduzierung oder mit dem Rahmen in der Größe verändert werden. Allerdings kann ein minimiertes Fenster, das nicht in der Taskleiste angezeigt wird, auf dem Desktop hin und her verschoben werden.

Ein Fenster mit einem maximiertenZustand wird auf die maximal mögliche Größe erweitert, die nur so groß ist, wie es seineMaxWidth, MaxHeight, und SizeToContent-Eigenschaften vorgeben. Wie ein minimiertes Fenster kann auch ein maximiertes Fenster nicht mithilfe des Ziehpunkts zur Größenänderung oder durch Ziehen des Rahmens in seiner Größe verändert werden.

Hinweis

Die Werte der Top, Left, Width, und Height-Eigenschaften und eines Fensters stellen immer die Werte für den normalen Zustand dar, auch wenn das Fenster derzeit maximiert oder minimiert ist.

Der Zustand eines Fensters kann durch Festlegen der WindowState-Eigenschaft konfiguriert werden, die einen der folgenden WindowState Enumerationswerte haben kann:

Im folgenden Beispiel wird veranschaulicht, wie Sie ein Fenster erstellen, das beim Öffnen als maximiert angezeigt wird.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    WindowState="Maximized">
</Window>

Im Allgemeinen sollten Sie festlegen, WindowState um den Anfangszustand eines Fensters zu konfigurieren. Wenn ein in der Größe veränderbares Fenster angezeigt wird, können die Benutzer die Schaltflächen zum Minimieren, Maximieren oder Wiederherstellen auf der Titelleiste des Fensters aktivieren, um den Fensterzustand zu ändern.

Fensterdarstellung

Sie ändern die Darstellung des Clientbereichs eines Fensters, indem Sie fensterspezifischen Inhalt hinzufügen, z. B. Schaltflächen, Bezeichnungen und Textfelder. Zur Konfiguration des Nicht-Client-Bereichs Windowstehen mehrere Eigenschaften zur Verfügung, u. a. Icon zum Einstellen des Fenstersymbols Title und des Fenstertitels.

Außerdem können Sie die Darstellung und das Verhalten des Rahmens im Nicht-Clientbereich ändern, indem Sie den Größenänderungsmodus, den Fensterstil und die Tatsache konfigurieren, ob es als Schaltfläche in der Desktoptaskleiste angezeigt wird.

Größenänderungsmodus

Abhängig von der WindowStyle -Eigenschaft können Sie steuern, ob und wie Benutzer die Größe des Fensters ändern. Der Fensterstil wirkt sich auf Folgendes aus:

  • Erlauben oder verbieten Sie die Größenänderung, indem Sie den Fensterrand mit der Maus bewegen.
  • Gibt an ob die SchaltflächenMinimieren, Vergrößern, und Schließen auf dem Nicht-Client-Bereich erscheinen.
  • Gibt an ob die SchaltflächenMinimieren, Vergrößern, und Schließen aktiviert sind.

Sie können konfigurieren, wie die Größe eines Fensters geändert wird, indem Sie dessen ResizeMode-Eigenschaft festlegen. Dies kann einer der folgenden ResizeMode Enumerationswerte sein:

Wie bei WindowStyle ändert sich der Größenänderungsmodus eines Fensters während der Lebensdauer kaum. Folglich werden Sie diesen wahrscheinlich über das XAML-Markup festlegen.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    ResizeMode="CanResizeWithGrip">
</Window>

Beachten Sie, dass Sie erkennen können, ob ein Fenster maximiert, minimiert oder wiederhergestellt wird, indem Sie die WindowState-Eigenschaft überprüfen.

Window style

Der Rahmen, der vom Nicht-Clientbereich eines Fensters verfügbar gemacht wird, eignet sich für die meisten Anwendungen. Unter bestimmten Umständen werden je nach Fenstertyp dennoch andere Rahmentypen oder überhaupt keine Rahmen benötigt.

Um zu steuern, welchen Rahmentyp ein Fenster erhält, legen Sie dessen WindowStyle-Eigenschaft mit einem der folgenden Werte der -Enumeration WindowStyle fest:

Die Auswirkung der Anwendung eines Fensterstils wird in der folgenden Abbildung veranschaulicht:

Screenshot that shows how WindowStyle affects a window in WPF.

Beachten Sie, dass das obige Bild keinen erkennbaren Unterschied zwischen SingleBorderWindow und ThreeDBorderWindow zeigt. Zurück in Windows XP hat ThreeDBorderWindow beeinflusst, wie das Fenster gezeichnet wurde, indem dem Clientbereich ein 3D-Rahmen hinzugefügt wurde. Ab Windows 7 sind die Unterschiede zwischen den beiden Stilen minimal.

Sie können WindowStyle festlegen, indem Sie entweder XAML-Markup oder Code verwenden. Da es unwahrscheinlich ist, dass sich dies während der Lebensdauer eines Fensters ändert, konfigurieren Sie es wahrscheinlich mit XAML-Markup.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    WindowStyle="ToolWindow">
</Window>

Nicht rechteckiger Fensterstil

Es gibt auch Situationen, in denen vonWindowStyle erlaubten Rahmenstile nicht ausreichend sind. Sie möchten z. B. eine Anwendung mit einem nicht rechteckigen Rahmen erstellen, wie er von Microsoft Windows Media Player verwendet wird.

Betrachten Sie beispielsweise das Sprechblasenfenster im folgenden Image:

Screenshot of a WPF window that has a clipped area and custom shape.

Dieser Fenstertyp kann, indem man den Parameter derWindowStyle-Eigenschaft aufNone einstellt, und durch die Verwendung einer speziellen Unterstützung, die Window für Transparenz hat.

<Window x:Class="WindowsOverview.ClippedWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ClippedWindow" SizeToContent="WidthAndHeight"
        WindowStyle="None" AllowsTransparency="True" Background="Transparent">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>

        <Rectangle Stroke="#FF000000" RadiusX="10" RadiusY="10"/>
        <Path Fill="White" Stretch="Fill" Stroke="#FF000000" HorizontalAlignment="Left" Margin="15,-5.597,0,-0.003" Width="30" Grid.Row="1" Data="M22.166642,154.45381 L29.999666,187.66699 40.791059,154.54395"/>
        <Rectangle Fill="White" RadiusX="10" RadiusY="10" Margin="1"/>
        
        <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="25" Text="Greetings!" TextWrapping="Wrap" Margin="5,5,50,5"/>
        <Button HorizontalAlignment="Right" VerticalAlignment="Top" Background="Transparent" BorderBrush="{x:Null}" Foreground="Red" Content="❌" FontSize="15" />

        <Grid.Effect>
            <DropShadowEffect BlurRadius="10" ShadowDepth="3" Color="LightBlue"/>
        </Grid.Effect>
    </Grid>
</Window>

Durch diese Kombination von Werten wird das Fenster angewiesen, ein transparentes Rendering zu übernehmen. In diesem Zustand können die Nicht-Clientbereichs-Adornmentschaltflächen des Fensters nicht verwendet werden, und Sie müssen Ihre eigenen angeben.

Vorhandensein der Taskleiste

Die Standarddarstellung eines Fensters umfasst eine Taskleistenschaltfläche. Einige Arten von Fenstern verfügen nicht über eine Taskleistenschaltfläche, z. B. Meldungsfelder, Dialogfelderoder Fenster, für die die WindowStyle -Eigenschaft auf festgelegt ToolWindow ist. Sie können steuern, ob die Taskleistenschaltfläche für ein Fenster angezeigt wird, indem Sie die ShowInTaskbar-Eigenschaft, die standardmäßig auftruefestgelegt ist, einstellen.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    ShowInTaskbar="False">
</Window>

Andere Fenstertypen

NavigationWindow ist ein Fenster, das zur Aufnahme von navigierbarem Inhalt bestimmt ist.

Dialogfelder sind Fenster, die häufig zum Erfassen von Benutzerinformationen verwendet werden, um eine Funktion ausführen. Wenn ein Benutzer beispielsweise eine Datei öffnen möchte, wird das Dialogfeld Datei öffnen von einer Anwendung angezeigt, um den Dateinamen vom Benutzer zu erhalten. Weitere Informationen finden Sie unter Übersicht über Dialogfelder.

Weitere Informationen