Dieser Artikel kann URLs enthalten, die bei der ursprünglichen Veröffentlichung gültig waren, aber jetzt mit Websites oder Seiten verknüpft sind, die nicht mehr vorhanden sind. Um den Ablauf des Artikels aufrechtzuerhalten, haben wir diese URLs im Text belassen, aber die Links deaktiviert.

MSDN Magazine

Windows Forms: Ein Modern-Day-Programmiermodell zum Schreiben von GUI-Anwendungen

Jeff Prosise
In diesem Artikel wird davon ausgegangen, dass Sie mit Visual Basic und C vertraut sind.#
Schwierigkeitsgrad 1 2 3
Durchsuchen Sie den Code für diesen Artikel unter Code Center: Windows Forms Demo
ZUSAMMENFASSUNG Zum Schreiben von GUI-Anwendungen für Microsoft .NET verwenden Sie Windows Forms. Windows Forms sind ein neuer Anwendungsstil, der um Klassen im System.WinForms-Namespace der .NET Framework-Klassenbibliothek erstellt wird. Sie verfügen über ein eigenes Programmiermodell, das sauberer, robuster und konsistenter ist als Modelle, die auf der Win32-API oder MFC basieren, und sie werden in der verwalteten Umgebung der .NET Common Language Runtime (CLR) ausgeführt. In diesem Artikel wird beschrieben, worum es in Windows Forms geht, vom Programmiermodell über die Microsoft Intermediate Language bis hin zum JIT-Compiler. Zwei Anwendungen, die Formulare, Ereignishandler, Anker und Persistenz verwenden, werden Schritt für Schritt erstellt.
Ich habe die Zukunft gesehen, und es hat Microsoft® .NET überall geschrieben. Falls Sie noch nichts gehört haben, ist Microsoft .NET eine neue Plattform, die sich auf Windows® befindet. Es ist ein völlig neues Programmierparadigma, das die Art und Weise, wie Sie windowsbasierte Software schreiben, verändern wird. Und es ist eine mutige neue Denkweise, bei der die Windows-API, MFC, ATL und andere Tools, auf die Sie sich bisher verlassen, eine neue API in den Hintergrund treten, die in einer Reihe von Klassen namens .NET Framework-Klassenbibliothek verkörpert ist. Was haben Sie davon? Ein einheitliches Programmiermodell, verbesserte Sicherheit und eine bessere Möglichkeit, umfassende Web-Apps mit vollem Funktionsumfang zu schreiben. Und das ist nur für den Anfang.
      Eines der Features von Microsoft .NET, die mich am meisten interessiert, ist Windows Forms. Wenn Sie ein alter MFC-Hack (oder Windows-API) wie ich sind, sind Windows Forms eine großartige Möglichkeit, mit der .NET Framework-Klassenbibliothek zu beginnen, da sie es Ihnen ermöglichen, herkömmliche GUI-Anwendungen zu schreiben, die Fenster erstellen, Benutzereingaben verarbeiten usw. Und sobald Sie Windows Forms gelernt haben, finden Sie auch das Erlernen anderer Teile des .NET Framework einfacher.
      Der Hauptvorteil des Schreibens von Windows-basierten Anwendungen auf Windows Forms Weise besteht darin, dass Windows Forms das Programmiermodell homogenisieren und viele der Fehler, Macken und Inkonsistenzen beseitigen, die die Windows-API plagen. Beispielsweise weiß jeder erfahrene Windows-basierte Programmierer, dass bestimmte Fensterstile nur beim Erstellen dieses Fensters auf ein Fenster angewendet werden können. Windows Forms solche Inkonsistenzen weitgehend beseitigen. Wenn Sie eine Formatvorlage, die nur bei der Erstellung sinnvoll ist, auf ein vorhandenes Fenster anwenden, zerstört Windows Forms das Fenster in aller Ruhe und erstellen es mit der angegebenen Formatvorlage neu. Darüber hinaus ist die .NET Framework Klassenbibliothek viel umfangreicher als die Windows-API, und wenn Sie Anwendungen mit Windows Forms schreiben, stehen Ihnen die volle Leistungsfähigkeit des Frameworks zur Verfügung. In den meisten Fällen benötigen Anwendungen, die mit Windows Forms geschrieben wurden, weniger Code als Anwendungen, die die Windows-API oder MFC verwenden.
      Ein weiterer Vorteil von Windows Forms ist, dass Sie dieselbe API verwenden, unabhängig davon, für welche Programmiersprache Sie sich entscheiden. In der Vergangenheit hat Ihre Wahl der Programmiersprache Ihre Wahl der API vorangetrieben. Wenn Sie in Visual Basic® programmiert haben, verwenden Sie eine API (die in der Visual Basic-Sprache verkörperte API), während C-Programmierer die Win32-API® und C++-Programmierer im Großen und Ganzen MFC verwendet haben. Für einen MFC-Programmierer war es schwierig, zu Visual Basic zu wechseln oder umgekehrt. Nicht mehr. Alle Anwendungen, die Windows Forms verwenden, werden in eine API geschrieben– die der .NET Framework-Klassenbibliothek. Die Sprache ist kaum mehr als eine Wahl des Lebensstils, und die Kenntnisse einer API reichen aus, um einem Programmierer das Schreiben von Anwendungen in praktisch jeder von ihnen gewählten Sprache zu ermöglichen.
      Windows Forms sind nichts anderes als ein modernes Programmiermodell für GUI-Anwendungen. Im Gegensatz zum Win32-Programmiermodell, von dem ein großteils auf Windows 1.0 zurückgeht, wurde dieses Modell mit dem Vorteil des Rückblicks entworfen.
      Der Zweck dieses Artikels besteht darin, das Windows Forms Programmiermodell vorzustellen. Zum Kompilieren und Ausführen der Codebeispiele muss das Microsoft .NET Framework SDK auf Ihrem Computer installiert sein. Sie können das .NET Framework SDK Beta 1 im Microsoft .NET Developer Center unter https://msdn.microsoft.com/netherunterladen.

Das Windows Forms Programmiermodell

      In Windows Forms ist der Begriff "form" ein Synonym für ein Fenster auf oberster Ebene. Das Standard Fenster einer Anwendung ist ein Formular. Alle anderen Fenster der obersten Ebene, über die die Anwendung verfügt, sind ebenfalls Formulare. Dialogfelder werden auch als Formulare betrachtet. Trotz ihres Namens müssen Anwendungen, die Windows Forms verwenden, nicht wie Formulare aussehen. Wie herkömmliche Windows-basierte Anwendungen haben Apps die volle Kontrolle über das, was in ihren Fenstern angezeigt wird.
      Programmierer sehen Microsoft .NET über die Linse der .NET Framework Klassenbibliothek. Stellen Sie sich MFC eine Größenordnung größer vor, und Sie erhalten ein genaues Bild von der Breite und Tiefe der .NET Framework Klassenbibliothek. Um Benennungskonflikte zu minimieren und organization für die vielen hundert Klassen zu verleihen, wird die .NET Framework Klassenbibliothek in hierarchische Namespaces unterteilt. Der Stammnamespace System definiert die grundlegenden Datentypen, die von allen .NET-Anwendungen verwendet werden.
      Anwendungen, die Windows Forms verwenden, sind stark von Klassen im System.WinForms-Namespace abhängig. Dieser Namespace enthält Klassen wie Form, die das Verhalten von Fenstern oder Formularen modelliert. Menü, das Menüs darstellt; und Zwischenablage, die es Windows Forms Anwendungen ermöglicht, auf die Zwischenablage zuzugreifen. Es enthält auch zahlreiche Klassen, die Steuerelemente mit Namen wie Button, TextBox, ListView und MonthCalendar darstellen. Auf diese Klassen kann nur mithilfe ihrer Klassennamen oder mit vollqualifizierten Namen wie System.WinForms.Button verwiesen werden.
      Im Mittelpunkt fast jeder Windows Forms-basierten Anwendung steht eine von System.WinForms.Form abgeleitete Klasse. Ein instance dieser Klasse stellt das Standard Fenster der Anwendung dar. System.WinForms.Form verfügt über eine Vielzahl von Eigenschaften und Methoden, die eine umfangreiche programmgesteuerte Schnittstelle zu Formularen umfassen. Möchten Sie die Dimensionen des Clientbereichs eines Formulars kennen? In Windows rufen Sie die GetClientRect-API-Funktion auf. In Windows Forms lesen Sie die ClientRectangle- oder ClientSize-Eigenschaft des Formulars. Viele Eigenschaften können sowohl geschrieben als auch gelesen werden. Sie können beispielsweise die Rahmenformatvorlage eines Formulars ändern, indem Sie in die BorderStyle-Eigenschaft schreiben oder die Größe eines Formulars mithilfe der Size- oder ClientSize-Eigenschaft ändern.
      Windows Forms-basierten Anwendungen, die Drucktasten, Listenboxen und andere Windows-Steuerelementtypen verwenden, basieren auf den Steuerelementklassen in System.WinForms. Sie werden diese Klassen lieben, weil sie die Steuerungsprogrammierung erheblich vereinfachen. Möchten Sie eine stilisierte Schaltfläche mit einem Bitmaphintergrund erstellen? Kein Problem. Umschließen Sie einfach ein Bild in ein System.Drawing.Bitmap-Objekt, und weisen Sie es der BackgroundImage-Eigenschaft der Schaltfläche zu. Wie sieht es mit Steuerelementfarben aus? Haben Sie jemals versucht, die Hintergrundfarbe eines Bearbeitungssteuerelements anzupassen? Ich weiß, dass andere Entwickler haben, weil ich immer eine E-Mail bekomme, die mich darüber fragt. In Windows Forms ist es einfach: Sie schreiben die Farbe einfach in eine Eigenschaft namens BackColor und lassen den Rest vom Framework erledigen.
      Ein weiterer wichtiger Baustein einer Anwendung, die Windows Forms verwendet, ist eine System.WinForms-Klasse namens Application. Diese Klasse enthält eine statische Methode mit dem Namen Run, die eine Windows Forms-basierte Anwendung durch Anzeigen eines Fensters und Bereitstellen einer Nachrichtenschleife abruft. Natürlich wird die Nachrichtenschleife nicht angezeigt. Die Existenz von Nachrichten wird in der .NET-Umgebung abstrahiert. Aber es ist da, und es ist ein weiteres Detail, um das Sie sich keine Sorgen machen müssen, da die Plattform diese Details für Sie verschwitzt.
      Aber warten Sie eine Minute – wenn Anwendungen, die Windows Forms sind, keine Nachrichten verarbeiten, wie reagieren sie auf Benutzereingaben oder wissen, wann sie zeichnen müssen? Zunächst verfügen viele Klassen über virtuelle Methoden, die Sie überschreiben können, um auf Malnachrichten, Mausnachrichten usw. zu reagieren. System.WinForms.Form enthält beispielsweise eine virtuelle Methode namens OnPaint, die aufgerufen wird, wenn der Clientbereich eines Formulars aktualisiert werden muss. OnPaint ist eine von vielen virtuellen Methoden, die Sie in einer abgeleiteten Klasse zum Erstellen interaktiver Formulare überschreiben können. OnMouseDown, OnKeyDown und OnClosing sind einige der anderen. Wenn alles andere fehlschlägt, bietet Windows Forms sogar einen Mechanismus zum Reagieren auf Windows-Nachrichten durch Tippen auf die interne Fensterprozedur eines Formulars.
      Ein weiteres wichtiges Facet des Windows Forms Programmiermodells ist der Mechanismus, den Formulare verwenden, um auf Eingaben aus Menüs, Steuerelementen und anderen GUI-Anwendungselementen zu reagieren. Herkömmliche Windows-basierte Anwendungen verarbeiten WM_COMMAND und WM_NOTIFY Nachrichten mithilfe von Windows Forms Prozessereignissen. In C# und in anderen Sprachen, die die .NET Common Language Runtime (CLR) unterstützen, sind Ereignisse erstklassige Typmember, die Methoden, Feldern und Eigenschaften entsprechen. Praktisch alle Windows Forms-Steuerelementklassen (und auch viele Nicht-Steuerungsklassen) auslösen Ereignisse. Beispielsweise lösen Schaltflächensteuerelemente – Instanzen von System.WinForms.Button – Click-Ereignisse aus, wenn sie geklickt werden. Ein Formular, das auf Schaltflächenklicks reagieren möchte, kann die folgende Syntax verwenden, um eine Schaltfläche mit einem Click-Handler zu verknüpfen:
  MyButton.Click += new EventHandler (OnButtonClicked);
  •••
private void OnButtonClicked (object sender, EventArgs e)
{
    MessageBox.Show ("Click!");
}

      EventHandler ist ein im Systemnamespace definierter Delegat. Ein Delegat ist das Äquivalent der CLR zu einem typsicheren Funktionszeiger. Dieses Beispiel umschließt einen EventHandler um die OnButtonClicked-Methode und fügt ihn der Liste der Ereignishandler hinzu, die aufgerufen werden, wenn MyButton ein Click-Ereignis auslöst. Der erste Parameter von OnButtonClick identifiziert das Objekt, das das Ereignis ausgelöst hat. Der zweite Parameter ist für Click-Ereignisse grundsätzlich bedeutungslos, wird aber von bestimmten anderen Ereignistypen verwendet, um zusätzliche Informationen zum Ereignis zu übergeben.

Hallo Welt mit Windows Forms

      Wenn Sie also eine neue Plattform lernen, spricht nichts besser als eine Hallo Welt Anwendung. (Ganze Unternehmen, insbesondere Dot-com-Startups, wurden um Hallo Welt Anwendungen herum aufgebaut.) Abbildung 1 enthält die Windows Forms Version einer Hallo Welt-App. Alle Beispiele in diesem Artikel sind in C# geschrieben, aber Sie können Windows Forms-basierte Anwendungen in jeder Sprache schreiben, für die ein .NET-Compiler verfügbar ist. Heute können Sie die Sprachen C#, Visual Basic, JScript® und verwaltetes C++ auswählen.
      Das Wichtigste zuerst. Mit den using-Anweisungen am Anfang der Datei können Sie auf Klassen in den Namespaces System, System.WinForms und System.Drawing verweisen, indem Sie nur deren Klassennamen verwenden. Ohne die folgende Anweisung, z. B.
  using System.WinForms;

Sie müssten schreiben
  public class MyForm : System.WinForms.Form

anstelle von
  public class MyForm : Form

      In einer Anwendung, die Windows Forms verwendet, wird jedes Fenster oder Formular durch eine instance einer klasse dargestellt, die von System.WinForms.Form abgeleitet ist. In Abbildung 1 ist diese Klasse MyForm. Der MyForm-Konstruktor legt den Untertitel Balkentext des Formulars auf "Windows Forms Demo" fest, indem er in die Text-Eigenschaft von MyForm schreibt. Text ist eine von mehr als 100 Eigenschaften, die das Formular von System.WinForms.Form erbt. Ich werde später weitere dieser Eigenschaften verwenden, aber für den Zeitpunkt ist Text das einzige, das Sie benötigen.
      Wie Sie wissen, erhalten Fenster WM_PAINT Nachrichten, und die meisten Bildschirmrenderings werden als Reaktion auf diese Nachrichten ausgeführt. In Windows Forms ist das Äquivalent einer WM_PAINT Nachricht eine virtuelle Methode namens OnPaint. Eine abgeleitete Formularklasse kann diese Methode überschreiben, um sich selbst als Reaktion auf WM_PAINT Nachrichten zu zeichnen.
      Beachten Sie die Außerkraftsetzung Schlüsselwort (keyword) in Abbildung 1, die vom C#-Compiler als Bestätigung interpretiert wird, dass Sie beabsichtigen, eine von einer Basisklasse geerbte virtuelle Methode außer Kraft zu setzen. Die OnPaint-Außerkraftsetzung schreibt hier "Hello, world" in den Clientbereich des Formulars. Wenn OnPaint aufgerufen wird, wird ein PaintEventArgs-Objekt (System.WinForms.PaintEventArgs) übergeben, das Eigenschaften namens Graphics und ClipRectangle enthält. Die Graphics-Eigenschaft enthält einen Verweis auf ein Graphics-Objekt (System.Drawing.Graphics), das die Windows Forms Entsprechung des Gerätekontexts darstellt. ClipRectangle enthält ein Rechteck (System.Drawing.Rectangle), das beschreibt, welcher Teil des Formulars ungültig ist.
      Die OnPaint-Methode von MyForm verwendet Graphics.DrawString, um die Ausgabe zu rendern. Der erste Parameter für DrawString ist die Zeichenfolge selbst. Das zweite ist ein Font-Objekt (System.Drawing.Font), das die Schriftart beschreibt, in der der Text gerendert werden soll. MyForm.OnPaint verwendet die Standardschriftart des Formulars, einen Verweis auf die in einer Form-Eigenschaft namens Font gespeichert wird. Der dritte Parameter ist ein Brush-Objekt (System.Drawing.Brush), das die Textfarbe angibt. MyForm.OnPaint erstellt ein schwarzes SolidBrush-Objekt (System.Drawing.SolidBrush) für diesen Parameter. Der vierte und letzte Parameter ist ein Formatierungsrechteck, das beschreibt, wo der Text positioniert werden soll. MyForm.OnPaint verwendet den gesamten Clientbereich des Formulars – eine Beschreibung, die sich in der Form-Eigenschaft mit dem Namen ClientRectangle befindet – als Formatierungsrechteck.
      Das letzte Element von MyForm ist eine statische Methode mit dem Namen Main. Main ist der Einstiegspunkt der Anwendung. Jede .NET-Anwendung muss über eine Main-Methode verfügen. Main kann auf eine der folgenden Arten deklariert werden:
  public static void Main ()
public static int Main ()
public static void Main (string[] args)
public static int Main (string[] args)

      Der an Main übergebene Args-Parameter ist ein Array von Zeichenfolgen, die die Befehlszeilenargumente der Anwendung darstellen. args[0] enthält den ersten Befehlszeilenparameter, args[1] den zweiten usw. Main wird in der Regel nur einmal in jeder Anwendung angezeigt, obwohl mehrere Main-Methoden definiert werden können, wenn Sie dem Compiler mitteilen, welcher Einstiegspunkt ist. (Der Microsoft C#-Compiler akzeptiert einen Schalter /Standard, der angibt, welche Klasse die Main-Methode enthält, die als Einstiegspunkt der Anwendung dient. Ein /Standard-Schalter ist nur erforderlich, wenn mehrere Klassen innerhalb der Anwendung Main-Methoden enthalten.) Main kann ein Member einer beliebigen Klasse sein, die in der Anwendung definiert ist.
      Das Anzeigen Ihres Formulars auf dem Bildschirm ist eine einfache Angelegenheit, um MyForm zu instanziieren und einen Verweis darauf an Application.Run zu übergeben. Application ist eine weitere Klasse, die im System.WinForms-Namespace definiert ist. Run ist die Methode, die Sie aufrufen, um ein Formular zu erstellen, es auf dem Bildschirm anzuzeigen und mit einer Nachrichtenschleife zu bedienen. In Abbildung 1 wird die folgende Anweisung
  Application.Run (new MyForm ());

instanziiert MyForm und zeigt das Formular an.
      Nachdem Sie den Code in Abbildung 1 eingegeben und in einer Datei namens Hello.cs gespeichert haben, müssen Sie ihn kompilieren. Öffnen Sie hierzu ein Eingabeaufforderungsfenster, wechseln Sie zu dem Ordner, in dem Hello.cs gespeichert ist, und geben Sie Folgendes ein:
  csc /target:winexe /out:Hello.exe /reference:System.dll
/reference:System.WinForms.dll /reference:System.Drawing.dll
/reference:Microsoft.Win32.Interop.dll Hello.cs

Der Befehl csc ruft den Microsoft C#-Compiler auf. Hello.cs identifiziert die zu kompilierte Datei. Der Schalter /target:winexe weist den Compiler an, eine windowsbasierte Gui-Anwendung (im Gegensatz zu einer Konsolenanwendung) zu erstellen, und /out:Hello.exe gibt den Namen der resultierenden ausführbaren Datei an. (Sie können diesen Schalter bei Bedarf weglassen, und die EXE wird weiterhin Hello.exe benannt, da die CS-Datei Hello.cs heißt. Die Schalter /reference identifizieren die Assemblys, in denen externe Typen wie System.WinForms.Form und System.Drawing.Size definiert sind. Aus Gründen der Kürze können Sie /target und /reference durch /t und /r ersetzen, wenn Sie möchten. Dennoch ist kein Weg an der Tatsache vorbei, dass das Erstellen von Befehlszeilenbuilds von Windows Forms-basierten Anwendungen ausführliche csc-Befehle erfordert.
      Hello.exe ist keine normale Windows-basierte EXE-Datei; Es handelt sich um eine ausführbare .NET-Datei, die die folgenden wichtigen Elemente enthält:
  • Die Microsoft Intermediate Language (MSIL), die aus Ihrem C#-Quellcode erstellt wird
  • Metadaten, die die in der Anwendung definierten Typen (Klassen) und die Typen (z. B. System.WinForms.Form) beschreiben, auf die in Ihrer Anwendung verwiesen wird, aber in anderen Assemblys (z. B. in MsCorLib.dll und System.WinForms.dll) gefunden werden.
  • Ein Manifest, das die Dateien beschreibt, aus denen die Assembly Ihrer Anwendung besteht.
      In der Sprache von .NET ist eine Assembly eine Sammlung einer oder mehrerer Dateien, die als Einheit bereitgestellt werden. Ihre Assembly enthält nur eine Datei – Hello.exe – und diese Tatsache wird in dem in die ausführbare Datei eingebetteten Manifest notiert. Das Manifest wird physisch als Teil der Metadaten gespeichert, aber ich behandle es hier als separate Entität, um seine Wichtigkeit zu unterstreichen. Jede verwaltete ausführbare Datei , d. h. jede PE-Datei, die MSIL enthält, ist Teil einer Assembly, und jede verwaltete ausführbare Datei enthält Metadaten. Eine der Dateien in einer .NET-Assembly enthält das Manifest, das die Dateien identifiziert, aus denen die Assembly besteht, die öffentlichen Datentypen, die diese Assembly anderen Assemblys zur Verfügung stellt, und andere Assemblys, von denen diese Assembly abhängt. Der C#-Compiler erzeugt diese gesamte erforderliche Infrastruktur für Sie, auch wenn Sie ihn nicht explizit dazu aufgefordert haben. Weitere Informationen zu Assemblys, Manifesten und Metadaten sowie zu den Rollen, die sie beim Betrieb von .NET-Anwendungen spielen, finden Sie unter Teil 1 und Teil 2 der Artikel von Jeffrey Richter zum .NET Framework in den Ausgaben september und oktober 2000 des MSDN® Magazine.
      Nachdem Hello.exe kompiliert wurde, können Sie sie ausführen, indem Sie folgendes eingeben:
  Hello

an der Eingabeaufforderung ein. Sehen Sie sich Abbildung 2 an, um zu sehen, wie das Ergebnis auf dem Bildschirm aussieht.

Abbildung 2 Hello.exe Wird ausgeführt
Abbildung 2Hello.exe Wird ausgeführt

Die ImageView-Anwendung

      Hallo Welt ist gut für den Anfang, aber Sie werden es schwer haben, damit Geld zu verdienen. (OK, ich habe scherzhaft gesagt, dass ganze Unternehmen um Hallo Welt Anwendungen herum erstellt wurden.) Lassen Sie uns also ernst nehmen und eine echte Anwendung mit Windows Forms schreiben – einem Bitmap-Viewer, der JPEG-Dateien, GIF-Dateien und verschiedene andere Arten von Bilddateien knacken kann. Ich nenne es ImageView, und ich werde die System.Drawing.Bitmap-Klasse der .NET Framework Klassenbibliothek verwenden, um die Vielzahl von Bilddateiformaten, die heute vorhanden sind, kurz zu verarbeiten. Die entsprechende Anwendung, die mit der Windows-API oder MFC geschrieben wurde, erfordert mehrere tausend Codezeilen. Mit Windows Forms werde ich es in ca. 100 Zeilen machen, einschließlich Schnickschnack.

Schritt 1: Erstellen eines Formulars

      Die In Abbildung 3 gezeigte Datei Main.cs enthält die ursprüngliche Version von ImageView. Es erstellt ein Formular, legt den Text in der Untertitel Leiste des Formulars auf "Bildanzeige" fest und formatiert das Formular so, dass der Clientbereich 640 x 480 Pixel misst. Die Größenanpassung erfolgt durch Schreiben eines Size-Werts (System.Drawing.Size) in die ClientSize-Eigenschaft, die MyForm von System.WinForms.Form erbt.
      Navigieren Sie zum Kompilieren zu dem Ordner, in dem Main.cs gespeichert ist, und geben Sie Folgendes ein:
    csc /target:winexe /out:ImageView.exe /reference:System.dll
  /reference:System.WinForms.dll /reference:System.Drawing.dll
  /reference:Microsoft.Win32.Interop.dll Main.cs

Dieses Mal verhindert der Schalter /out, dass die EXE-Datei Main.exe benannt wird. Nachdem ImageView.exe kompiliert wurde, führen Sie sie aus, indem Sie sie eingeben.
  ImageView

an der Eingabeaufforderung ein. Das Fenster, das Sie sehen, sieht im Moment ziemlich einfach aus, es fehlen herkömmliche GUI-Anwendungselemente wie ein Menü, aber Sie werden dies in der nächsten Übung beheben.

Schritt 2: Hinzufügen eines Menüs "Optionen"

      Der nächste Schritt besteht darin, ein Menü "Optionen" hinzuzufügen, das einen Exit-Befehl enthält, der die Anwendung schließt. In einer Anwendung, die Windows Forms verwendet, ist ein Menü auf oberster Ebene – die Menüleiste, die unter der Titelleiste des Fensters angezeigt wird – eine instance von System.WinForms.MainMenu. Ein MainMenu wird an ein Formular angefügt, indem es der Menu-Eigenschaft des Formulars zugewiesen wird, die das Formular von System.WinForms.Form erbt. Elemente im Menü werden durch MenuItem-Objekte (System.WinForms.MenuItem) dargestellt.
      Abbildung 4 zeigt die erforderlichen Änderungen an "Main.cs". Neuer Code wird im grünen Typ angezeigt. Die Anweisung
  MainMenu menu = new MainMenu ();

erstellt ein MainMenu-Objekt und speichert einen Verweis darauf in der Variablen namens menu. Die Anweisung
  MenuItem item = menu.MenuItems.Add ("&Options");

fügt ein Menüelement mit dem Titel &Optionen hinzu und speichert einen Verweis darauf in der Variablen namens item. MenuItems ist eine Auflistung, die alle im Menü enthaltenen Menüelemente darstellt. Durch Aufrufen von Add für diese Auflistung wird dem Menü ein Element hinzugefügt und ein MenuItem-Objekt zurückgegeben. Schließlich die -Anweisung
  item.MenuItems.Add (new MenuItem ("E&xit",
    new EventHandler (OnExit));

fügt dem Menü Optionen einen Exit-Befehl hinzu und verbindet ihn mit einem Handler namens OnExit. Bei der Ausführung ruft OnExit die Close-Methode des Formulars auf (die MyForm durch Vererbung abruft), wodurch das Formular geschlossen wird und die Anwendung letztendlich beendet wird.

Schritt 3: Hinzufügen eines Open-Befehls

      Die überarbeitete Version von Main.cs in Abbildung 5 fügt dem Menü Optionen den Befehl Öffnen hinzu. Das Hinzufügen des Menüelements ist eine einfache Angelegenheit des Aufrufens von Hinzufügen in der MenuItems-Auflistung des Menüs Optionen. Ein weiterer Aufruf von Add – diesmal mit "-" als Menüelementtext – fügt ein horizontales Trennzeichen hinzu. Beachten Sie den dritten Parameter, der an den MenuItem-Konstruktor übergeben wird:
  Shortcut.CtrlO

      Shortcut ist eine in System.WinForms definierte Enumeration. STRGO ist ein Element dieser Enumeration, das der Tastenkombination STRG+O entspricht. Das Einschließen von Shortcut.StrgO in die Parameterliste bewirkt zwei Dinge: Es definiert STRG+O als Verknüpfung für den Befehl Öffnen und fügt "STRG+O" an den Text des Menüelements an.
      Das Öffnen einer Bilddatei fällt auf OnOpenImage. Die openFileDialog-Klasse der .NET Framework Klassenbibliothek, die Teil des System.WinForms-Namespaces ist, kapselt die Funktionalität des Windows-Dialogfelds Datei öffnen und ermöglicht die Verwendung dieses Dialogfelds durch verwalteten Code. OnOpenImage erstellt ein OpenFileDialog-Objekt, initialisiert es mit einer Filterzeichenfolge, die angibt, was im Feld "Dateien vom Typ" des Dialogfelds angezeigt werden soll, und zeigt das Dialogfeld durch Aufrufen von OpenFileDialog.ShowDialog an. Wenn der Benutzer einen Dateinamen eingibt und auf OK klickt, extrahiert OnOpenImage den Dateinamen, indem er ihn aus der FileName-Eigenschaft von OpenFileDialog liest. Anschließend wird die Datei mit der Anweisung geöffnet:
  _MyBitmap = new Bitmap (fileName);

      Bitmap ist die Abkürzung für System.Drawing.Bitmap. Es handelt sich um eine leistungsstarke Klasse, die Bitmaps kapselt und das Einfache Öffnen von Bilddateien fast beliebiger Art durch Eingabe eines Dateinamens ermöglicht. Natürlich müssen Sie berücksichtigen, dass ein Benutzer möglicherweise eine Datei auswählt, die überhaupt keine Bilddatei ist. Aus diesem Grund ist diese Anweisung in einem Try-Block enthalten. Wenn der Benutzer eine Nicht-Bilddatei auswählt, löst der Bitmap-Klassenkonstruktor eine Ausnahme aus, die von Ihrem Catch-Handler abgefangen wird. Dadurch wird eine Fehlermeldung angezeigt, die den Benutzer darauf hinweist, dass es sich bei der Datei nicht um eine Bilddatei handelt. OnOpenImage zeigt die Fehlermeldung an, indem eine statische MessageBox-Methode mit dem Namen Show aufgerufen wird. MessageBox (System.WinForms.MessageBox) ist die Framework-Klasse, die Nachrichtenfelder umschließt.
      Beachten Sie den Aufruf von Invalidate, der ausgeführt wird, wenn die Imagedatei erfolgreich geöffnet wurde. Invalidate ist eine System.WinForms.Form-Methode, die eine Neubemalung erzwingt, indem der Clientbereich eines Formulars ungültig wird. Wie die InvalidateRect-Funktion in der Windows-API (und die CWnd::InvalidateRect-Funktion von MFC) kann Form.Invalidate verwendet werden, um ein gesamtes Formular oder nur einen Teil davon zu ungültig machen. Hier wird sie verwendet, um den gesamten Clientbereich zu ungültig zu machen.
      Nachdem ich nun einen Open-Befehl implementiert habe, würden Sie hoffen, dass ich ein Bild anzeigen kann. ImageView fehlt jedoch weiterhin Code zum Rendern des Bilds im Formular. Im Moment können Sie zumindest nachweisen, dass der Versuch... Catch Logic in Abbildung 5 funktioniert durch den Versuch, eine Nicht-Image-Datei zu öffnen. Sie können überprüfen, ob der Dateiname in der Titelleiste des Formulars angezeigt wird, wenn Sie eine Bilddatei auswählen. Dennoch ist ImageView von begrenztem Nutzen, wenn die Vom Benutzer geöffneten Bilder nicht angezeigt werden können. Lassen Sie uns dies mit dem Hinzufügen von Mallogik beheben.

Schritt 4: Überschreiben von OnPaint

      Zum Hinzufügen von Mallogik überschreiben Sie OnPaint in Ihrer abgeleiteten Formularklasse und verwenden das angegebene Graphics-Objekt. Die OnPaint-Methode in Abbildung 6 rendert _MyBitmap im Clientbereich des Formulars. (_MyBitmap, erinnern Sie sich, ist ein von OnOpenImage initialisiertes geschütztes Feld, das einen Verweis auf das vom Benutzer ausgewählte Bild speichert.) Das Rendering wird mit zwei einfachen Anweisungen ausgeführt:
  Graphics g = e.Graphics;
g.DrawImage (_MyBitmap, 0, 0,
    _MyBitmap.Width, _MyBitmap.Height);

      Das Ergebnis ist in Abbildung 7 dargestellt. Die Zeichnung erfolgt durch DrawImage, eine von vielen Methoden, die in System.Drawing.Graphics definiert sind. Das Zeichnen von Bitmaps auf dem Bildschirm ist in .NET viel einfacher als in Windows, vor allem, weil dem Windows GDI keine allgemeinen Funktionen zum Zeichnen und Bearbeiten von Bitmapbildern fehlen.

Abbildung 7 Bildansicht, in der eine JPEG-Datei angezeigt wird
Abbildung 7Bildansicht, in der eine JPEG-Datei angezeigt wird

      Wenn Sie ein Graphics-Objekt zum Rendern der grafischen Ausgabe verwenden, verwenden Sie eine Komponente der .NET-Plattform namens GDI+. Wie windows GDI ist GDI+ eine API zum Erstellen von 2D-Grafiken. Im Gegensatz zu Windows GDI ist GDI+ jedoch nicht durch den begrenzten Satz von Funktionen eingeschränkt, die aus Gdi32.dll exportiert werden. GDI+ ist erheblich reicher und enthält Unterstützung für Farbverlaufsfüllungen, Gleitkommakoordinaten, Antialiasing und vieles mehr. Es verwendet auch ein zustandsloses Programmiermodell, das es für die Verwendung in verteilten, verbindungslosen Anwendungen besser geeignet macht.

Schritt 5: Hinzufügen von Bildlaufleisten

      ImageView kann nun Bilder anzeigen, aber wenn die Bildgröße die Formulargröße überschreitet, kann nur ein Teil des Bilds angezeigt werden. Eine offensichtliche Lösung für dieses Problem ist eine Reihe von Bildlaufleisten – eine horizontale Bildlaufleiste, die angezeigt wird, wenn die Bildbreite die Formularbreite überschreitet, und eine vertikale Scrollleiste, die angezeigt wird, wenn die Bildhöhe die Formularhöhe überschreitet.
      System.WinForms.Form erbt ein Eigenschaftenpaar von System.WinForms.ScrollableControl, die das Scrollen zum Kinderspiel machen. AutoScroll ist eine boolesche Eigenschaft, die die automatische Registrierung ein- und ausschaltet. Wenn die automatische Registrierung aktiviert ist, werden Bildlaufleisten automatisch angezeigt, wenn das Formular zu klein ist, um alles anzuzeigen, was Sie im Clientbereich wünschen. Woher weiß das Formular, was angezeigt werden soll? Sie weisen ihr die Dimensionen des gewünschten Anzeigebereichs zu, indem Sie einen Size-Wert in die AutoScrollMinSize-Eigenschaft des Formulars schreiben.
      Die in Abbildung 8 gezeigte Version von Main.cs fügt ImageView-Unterstützung für Bildlauf hinzu. OnOpenImage wurden zwei Codezeilen hinzugefügt: eine zum Aktivieren des automatischen Rollings und eine andere, um AutoScrollMinSize auf die Breite und Höhe der Bitmap festzulegen. OnPaint wurde auch so geändert, dass die Bitmap um einen Betrag versetzt wird, der den horizontalen und vertikalen Bildlaufpositionen entspricht. Diese einfachen Änderungen ermöglichen es, jedes Bild in seiner Gesamtheit anzuzeigen, unabhängig davon, wie groß das Bild oder wie klein das Format ist.

Schritt 6: Hinzufügen einer Option "Größe an Anpassung"

      Das Hinzufügen von Bildlaufleisten zum Formular ist eine Möglichkeit, große Bilder zu verarbeiten. Eine weitere Option besteht darin, die physische Größe des Bilds zu ignorieren und es so zu rendern, dass es genau in das Formular passt. Lassen Sie den Benutzer entscheiden, wie er dies behandeln soll, indem er dem Menü Optionen ein Befehlspaar hinzufügt. Ein Befehl, Bild an Fenster anpassen, passt das Bild an das Formular an. Die andere, Bild in nativer Größe anzeigen, zeigt Bilder in ihrer nativen Auflösung an, stellt jedoch (falls erforderlich) Bildlaufleisten bereit, um die Anzeige großer Bilder zu ermöglichen.
      Abbildung 9 zeigt die Vorgehensweise. Zuerst fügen Sie ein Feld (_NativeSize) hinzu, um die Benutzereinstellung zu speichern. Als Nächstes ändern Sie den MyForm-Konstruktor, um zwei neue Menüelemente hinzuzufügen (drei, wenn Sie die zusätzliche Trennleiste zählen). Drittens fügen Sie Befehlshandler hinzu, die _NativeSize auf true oder false festlegen, den Bildlauf aktivieren oder deaktivieren und Invalidate aufrufen, um eine Neubemalung zu erzwingen. Schließlich ändern Sie OnPaint so, dass die Größe des gerenderten Bilds der Formulargröße entspricht, wenn _NativeSize false ist. Das Abgleichen der Bildgröße mit der Formulargröße ist eine einfache Angelegenheit der Übergabe eines Rechtecks, das die Dimensionen des Clientbereichs des Formulars im zweiten Parameter von DrawImage enthält. Dieses Rechteck ist leicht als System.WinForms.Form-Eigenschaft namens ClientRectangle verfügbar.
      Der einzige neue Code in Abbildung 9 , der eine Augenbraue auslösen könnte, ist ein Paar Aufrufe von SetStyle. Aus diesem Grund habe ich sie hinzugefügt. Standardmäßig wird bei einem Vorgang zur Größenänderung nicht das gesamte Formular ungültig. Es ungültigiert nur den Teil des Formulars, der durch den Größenänderungsvorgang verfügbar gemacht wird. Dies ist in Ordnung, wenn Sie das Bild nicht an die Formulargröße skalieren, aber wenn Sie dies tun, möchten Sie, dass der gesamte Clientbereich ungültig wird, wenn sich seine Größe ändert, sodass das gesamte Formular neu gestrichen wird. In Windows würden Sie dies erreichen, indem Sie CS_HREDRAW- und CS_ VREDRAW-Flags im WNDCLASS-Stil einschließen. In Windows Forms rufen Sie dazu die SetStyle-Methode des Formulars mit einem ControlStyles.ResizeRedraw-Parameter auf. ControlStyles ist eine in System definierte Enumeration. Winforms; ResizeRedraw ist ein Element dieser Enumeration.

Schritt 7: Hinzufügen von Code zum Aktivieren und Deaktivieren von Menüelementen

      Es bleibt nur noch, ein Häkchen neben dem Befehl Fenster anpassen oder Bild in nativer Größe anzeigen zu platzieren, je nachdem, ob _NativeSize true oder false ist. Es gibt zwei Möglichkeiten, wie Sie dies ausführen können.
      Die erste Option besteht darin, die Check-Eigenschaft jeder MenuItem-Eigenschaft auf true oder false festzulegen, wenn ein Element im Menü ausgewählt ist. Wenn Sie "Überprüft" gleich "true" festlegen, wird ein Häkchen neben dem entsprechenden Menüelement gesetzt. Wenn sie auf false festgelegt wird, wird die Kontrollkästchen deaktiviert. Die andere Option besteht darin, die Menüelemente in der Mikrosekunde zwischen dem Klicken des Benutzers auf Optionen im menü Standard zu aktivieren oder zu deaktivieren, und das Menü Optionen wird auf dem Bildschirm angezeigt, d. h. schreiben Sie das Äquivalent eines MFC-Updatehandlers. Letzteres hat den eindeutigen Vorteil, dass der Code, der das Menü aktualisiert, von dem Code entkoppelt wird, der _NativeSize auf true oder false festlegt. Dies ist der Ansatz in Abbildung 10.
      In dieser, der endgültigen Version von Main.cs, werden Verweise auf die MenuItem-Objekte, die die Befehle Size Image to Fit Window und Show Image in Native Size darstellen, in Feldern mit dem Namen _itemFitToWindow bzw. _itemNativeSize zwischengespeichert. Darüber hinaus ist ein Handler für Popupereignisse – Ereignisse, die anzeigen, dass ein Menü heruntergezogen wurde – mit der folgenden Anweisung mit dem Menü Optionen verbunden:
    item.Popup += new EventHandler 
     (OnPopupOptionsMenu);

      OnPopupOptionsMenu, das immer dann aufgerufen wird, wenn das Menü Optionen angezeigt wird, überprüft oder deaktiviert die Menüelemente, die von _itemFitToWindow dargestellt werden, und _itemNativeSize basierend auf dem aktuellen Wert von _NativeSize. Folglich wird das Häkchen immer neben dem richtigen Menüelement angezeigt, unabhängig davon, wie der aktuelle Wert von _NativeSize ist oder wie dieser Wert abgerufen wurde. Das fertige Produkt ist in Abbildung 11 dargestellt.

Abbildung 11 Bild in nativer Größe anzeigen überprüft
Abbildung 11Bild in nativer Größe anzeigen überprüft

ImageView in Review

      Sie haben nun aus erster Hand gesehen, welche wichtigen Rollen die Klassen Form, Application und Graphics der .NET Framework Klassenbibliothek beim Betrieb einer Anwendung mit Windows Forms spielen. An diesem Punkt kann es hilfreich sein, einige der Frameworkklassen zu überprüfen, die ImageView verwendet. Abbildung 12 zeigt eine partielle Liste dieser Klassen, die den Entwurf und den Vorgang von ImageView am meisten prägen. Wenn Sie Microsoft .NET-Programmierer werden, müssen Sie vor allem die .NET Framework Klassenbibliothek kennen lernen, und Sie kennen wahrscheinlich bereits die Windows-API, MFC oder die Visual Basic-API. In einem sehr realen Sinne ist die .NET Framework Klassenbibliothek die .NET-API. Es ist der Schlüssel, der die Box namens Microsoft .NET entsperrt, und wenn Microsoft mitredet, ist es das Substrat, das die Grundlage für zukünftige Generationen von Windows-basierten Anwendungen und Webanwendungen bilden wird.

Die TuneTown-Anwendung

      Das Schreiben einer Anwendung wie ImageView ist eine gute Möglichkeit, um mit Windows Forms zu beginnen, aber es ist nur das – ein Anfang. ImageView verwendet nur eine Handvoll der Windows Forms Klassen, die im .NET Framework verfügbar sind, und es handelt sich nicht um eine herkömmliche formularbasierte Anwendung in dem Sinne, dass sie keine Drucktasten oder Steuerelemente eines beliebigen Typs verwendet. Dies können wir durch das Schreiben einer zweiten Anwendung, die Steuerelemente verwendet, eine Anwendung, mit der ein Benutzer seine CD-Sammlung katalogisieren kann (siehe Abbildung 13). Dieses Mal nutzen Sie die volle Leistungsfähigkeit von Microsoft Visual Studio .NET, um das Problem zu beheben, indem Sie ihre IDE verwenden, um Ihre Formulare zu entwerfen und den Code zu generieren, der sie sichert.

Abbildung 13 CD-Sammlungskatalog
Abbildung 13CD-Sammlungskatalog

      Die folgenden Übungen wurden unter Verwendung der Beta 1-Version von Visual Studio .NET geschrieben, die Microsoft im November 2000 zum Herunterladen zur Verfügung gestellt hat. Es ist möglich, dass sich die hier angezeigten Bildschirme und sogar die Mechanik der Übungen selbst ändern, bevor Visual Studio .NET fertig gestellt und veröffentlicht wird.

Schritt 1: Erstellen eines neuen Windows Forms-Projekts

      Wählen Sie im Visual Studio-Menü® Datei den Befehl Neues Projekt aus, um ein neues Projekt zu erstellen. Wählen Sie windows-Anwendung aus dem Ordner C#-Projekte als Projekttyp aus (siehe Abbildung 14). Geben Sie als Projektname TuneTown ein.

Abbildung 14 Neues Projekt erstellen
Abbildung 14Neues Projekt erstellen

Schritt 2: Entwerfen des Hauptformulars

      Sobald das neue Projekt erstellt wurde, werden Sie von Visual Studio in den Visual Studio-Formular-Editor gebracht und ein leeres Formular angezeigt. Bevor Sie mit der Arbeit am Formular beginnen, ändern Sie den Dateinamen Main1.cs im fenster Projektmappen-Explorer in MainForm.cs. Wenn Sie gerade dabei sind, verwenden Sie das Fenster Klassenansicht, um den Namen der Formularklasse von Form1 in MainForm zu ändern.
      Wechseln Sie nun zurück zum Formular-Editor, und fügen Sie dem Formular ein Listenansicht-Steuerelement und drei Pushschaltflächen hinzu, wie in Abbildung 15 dargestellt. Wählen Sie dann nacheinander jedes der Steuerelemente aus, die Sie hinzugefügt haben, und verwenden Sie die Eigenschaftenfenster, um die Steuerelementeigenschaften wie in den folgenden Absätzen beschrieben zu ändern.

Abbildung 15 TuneTowns Hauptformular
Abbildung 15TuneTowns Hauptformular

      Bearbeiten Sie für das Listenansichtssteuerelement die Steuerelementeigenschaften wie folgt:
  1. Legen Sie die FullRowSelect-Eigenschaft auf True fest.
  2. Legen Sie die GridLines-Eigenschaft auf True fest.
  3. Legen Sie die View-Eigenschaft auf Bericht fest.
  4. Bearbeiten Sie die Columns-Auflistung, um der Kopfzeile oben in der Listenansicht drei Spalten hinzuzufügen: eine Spalte, deren Name "TitleHeader" lautet, deren Text "Title" ist und deren Width 100 ist; ein anderer, dessen Name "ArtistHeader", Text "Artist" und Width 100 ist; und ein drittes, dessen Name "CommentHeader", Text "Comment" und Width 200 ist.
  5. Legen Sie Multiselect auf False fest.
  6. Legen Sie HideSelection auf False fest.
  7. Legen Sie Sortierung auf Aufsteigend fest.
  8. Legen Sie TabIndex auf 0 fest.
  9. Legen Sie Name auf "TuneView" fest.
      Bearbeiten Sie die Eigenschaften der Schaltflächensteuerelemente wie folgt:
  1. Legen Sie die Text-Eigenschaft auf "&Hinzufügen", "&Bearbeiten" bzw. "&Entfernen" fest.
  2. Legen Sie die Name-Eigenschaft auf "AddButton", "EditButton" bzw. "RemoveButton" fest.
  3. Legen Sie die TabIndex-Eigenschaft auf 1, 2 bzw. 3 fest.
      Ändern Sie schließlich die Text-Eigenschaft des Formulars selbst in "TuneTown". Dadurch wird der Titel in der Untertitel leiste des Formulars geändert.

Schritt 3: Hinzufügen eines weiteren Formulars

      Sie benötigen ein zweites Formular, mit dem Sie Eingaben anfordern können, wenn der Benutzer auf die Schaltfläche Hinzufügen oder Bearbeiten klickt. In der Tat dient dieses Formular als Dialogfeld. Um das Formular zum Projekt hinzuzufügen, wechseln Sie zum Menü Projekt, wählen Sie den Befehl Windows Form hinzufügen aus, und wählen Sie im folgenden Dialogfeld Windows Form aus (siehe Abbildung 16). Geben Sie im Feld Name den Namen AddEditForm.cs ein.

Abbildung 16 Hinzufügen eines neuen Windows-Formulars
Abbildung 16Hinzufügen eines neuen Windows-Formulars

Schritt 4: Entwerfen des Formulars

      Bearbeiten Sie das neue Formular im Visual Studio-Formular-Editor, sodass es dem in Abbildung 17 dargestellten Formular ähnelt. Ändern Sie die Eigenschaften der Bezeichnungssteuerelemente wie folgt:

Abbildung 17 Formular-Editor
Abbildung 17Formular-Editor

  1. Legen Sie die Text-Eigenschaft auf "&Title", "&Artist" und "&Comment" fest.
  2. Legen Sie die Name-Eigenschaft auf "TitleLabel", "ArtistLabel" bzw. "CommentLabel" fest.
  3. Legen Sie TabIndex auf 0, 2 bzw. 4 fest.
      Ändern Sie die Eigenschaften der Bearbeitungssteuerelemente auf folgende Weise:
  1. Legen Sie die Texteigenschaften aller drei Steuerelemente auf NULL fest.
  2. Legen Sie Name auf "TitleBox", "ArtistBox" bzw. "CommentBox" fest.
  3. Legen Sie TabIndex auf 1, 3 bzw. 5 fest.
  4. Ändern Sie die Multiline-Eigenschaft des dritten Bearbeitungssteuerelements von False in True.
      Ändern Sie als Nächstes die Eigenschaften der beiden Drucktasten:
  1. Legen Sie Text auf "OK" bzw. "Abbrechen" fest.
  2. Legen Sie DialogResult auf OK bzw. Abbrechen fest.
  3. Legen Sie Name auf "OKButton" bzw. "NotOKButton" fest.
  4. Legen Sie TabIndex auf 6 bzw. 7 fest.
      Bearbeiten Sie schließlich die Eigenschaften des Formulars selbst:
  1. Legen Sie BorderStyle auf FixedDialog fest.
  2. Legen Sie AcceptButton auf OKButton fest.
  3. Legen Sie CancelButton auf NotOKButton fest.
  4. Legen Sie MaximizeBox und MinimizeBox auf False fest.
  5. Legen Sie ShowInTaskbar auf False fest.
      Die Formulare sind vollständig; jetzt ist es an der Zeit, Code zu schreiben.

Schritt 5: Hinzufügen von Eigenschaften zu AddEditForm

      Öffnen Sie AddEditForm.cs, und fügen Sie die Anweisungen hinzu, die in Abbildung 18 im grünen Typ angezeigt werden. Der Großteil des in Abbildung 18 gezeigten Codes wurde von Visual Studio erstellt. Dieser Code führt drei wichtige Aufgaben aus:
  • Sie deklariert die Felder Button (System.WinForms.Button), TextBox (System.WinForms.TextBox) und Label (System.WinForms.Label) in der AddEditForm-Klasse, um die Steuerelemente des Formulars darzustellen. Außerdem werden diese Felder mit Verweisen auf Instanzen von Button, TextBox und Label initialisiert.
  • Sie initialisiert die Eigenschaften jedes Steuerelements und des Formulars selbst.
  • Die Steuerelemente werden dem Formular physisch hinzugefügt, indem Add in der Controls-Auflistung des Formulars aufgerufen wird.
      Der größte Teil dieses Codes befindet sich in einer Methode namens InitializeComponent, die vom Klassenkonstruktor aufgerufen wird. Die "Komponente" in InitializeComponent bezieht sich auf das Formular selbst. Der meiste Code, der in der InitializeComponent-Methode angezeigt wird, wurde zu dem Zeitpunkt generiert, als Sie die Steuerelemente dem Formular hinzugefügt und die Eigenschaften der Steuerelemente geändert haben.
      Die von Ihnen eingegebenen Anweisungen fügen der Formularklasse die Eigenschaften Title, Artist und Comment hinzu. Diese Eigenschaften ermöglichen Aufrufern den Zugriff auf den Text in den Bearbeitungssteuerelementen des Formulars.

Schritt 6: Hinzufügen von Ereignishandlern zu MainForm

      Der nächste Schritt besteht darin, der MainForm-Klasse Ereignishandler hinzuzufügen– Handler, die aufgerufen werden, wenn auf die Schaltfläche Hinzufügen, Bearbeiten oder Entfernen geklickt wird oder wenn auf ein Element im Listenansichtssteuerelement doppelklicken (siehe Abbildung 19).
      In Windows Forms steuert Brandereignisse als Reaktion auf Benutzereingaben. MainForm verbindet das Click-Ereignis der einzelnen Pushbuttons mit einer XxxButtonClicked-Methode und das DoubleClick-Ereignis von ListView mit OnItemDoubleClicked. Die Handler für die Schaltflächen Hinzufügen und Bearbeiten instanziieren AddEditForm und zeigen es auf dem Bildschirm an, indem die ShowDialog-Methode aufgerufen wird. Der Rückgabewert von ShowDialog gibt an, wie das Dialogfeld geschlossen wurde: DialogResult.OK, wenn auf die Schaltfläche OK geklickt wurde, DialogResult.Cancel, wenn stattdessen auf Cancel geklickt wurde. Zum Abrufen von Daten in und aus dem Dialogfeld lesen und schreiben die Handler die Eigenschaften, die Sie addEditForm in Schritt 5 hinzugefügt haben. Erneut stellt der Formular-Editor den Code bereit, der die Darstellung des Formulars definiert, und Sie stellen den Code bereit, der das Verhalten implementiert.
      Jetzt ist ein guter Zeitpunkt, um das Projekt zu erstellen, wenn Sie dies noch nicht getan haben. Sie müssen nicht zur Befehlszeile wechseln. Stattdessen können Sie im Visual Studio-Menü Erstellen den Befehl Erstellen auswählen. Anschließend können Sie TuneTown.exe ausführen, indem Sie einen der Startbefehle des Menüs Debuggen auswählen.

Schritt 7: Hinzufügen von Ankern

      TuneTown ist fast vollständig, aber es fehlt noch ein wichtiges Element – ein Element, das eines der coolsten Features in Windows Forms hervorhebt. Um zu sehen, was ich meine, führen Sie die Anwendung aus, und ändern Sie die Größe des Standard Fensters. Die Größe des Fensters wird problemlos geändert (das liegt daran, dass die BorderStyle-Eigenschaft des Formulars auf Sizable festgelegt ist. Um eine Größenänderung zu verhindern, können Sie den BorderStyle in FixedDialog ändern), aber die Steuerelemente bleiben einfach. Wäre es nicht schön, wenn die Steuerelemente mit dem Formular fließen, die Größe automatisch ändern und sich neu positionieren würden, um alle ihnen zur Verfügung stehenden Immobilien zu nutzen? Um dies in einer herkömmlichen Windows-basierten Anwendung zu tun, müssten Sie WM_SIZE Nachrichten verarbeiten und die Steuerelemente programmgesteuert verschieben und die Größe ändern. In Windows Forms können Sie dies mit etwa einem Zehntel des Aufwands tun. Tatsächlich müssen Sie keine einzige Codezeile schreiben.
      Jedes Windows Form-Steuerelement erbt eine Eigenschaft namens Anchor von System.WinForms.RichControl. Die Anchor-Eigenschaft beschreibt, an welchen Kanten des übergeordneten Steuerelements die eigenen Kanten eines Steuerelements geklebt werden sollen. Wenn Sie beispielsweise die Anchor-Eigenschaft eines Steuerelements auf AnchorStyles.Right festlegen, bleibt der Abstand zwischen dem rechten Rand des Steuerelements und dem rechten Rand des Formulars konstant, auch wenn die Größe des Formulars geändert wird. Durch Festlegen der Ankereigenschaften der Steuerelemente in MainForm können Sie ganz einfach die Pushschaltflächen so konfigurieren, dass sie mit dem rechten Rand des Formulars verschoben werden, und das Listenansichtssteuerelement so, dass es sowohl vertikal als auch horizontal gestreckt wird, um den verbleibenden Platz im Formular auszufüllen. Gehen Sie folgendermaßen vor:
      Öffnen Sie MainForm im Formular-Editor, und wählen Sie die Anchor-Eigenschaft von ListView aus. Zunächst ist Anchor auf TopLeft festgelegt; Ändern Sie sie in Alle. Legen Sie dann einzeln die Ankereigenschaften der Pushbuttons auf TopRight fest. Diese Aktionen führen dazu, dass der InitializeComponent-Methode von MainForm die folgenden Anweisungen hinzugefügt werden:
    AddButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  EditButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  RemoveButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  TuneView.Anchor = System.WinForms.AnchorStyles.All;

      Erstellen Sie nun die Anwendung neu, und ändern Sie die Größe des Formulars erneut. Dieses Mal sollten die Steuerelemente mit dem Formular fließen. Ich bin sicher, dass Sie von Dialogen frustriert waren, deren Steuerelemente zu klein sind, um alles anzuzeigen, was Sie anzeigen möchten. Frustrationen wie diese gehören der Vergangenheit an, wenn Entwickler Windows Forms Verankerung nutzen.

Schritt 8: Hinzufügen von Persistenz

      Der letzte Schritt besteht darin, die in TuneTown eingegebenen Daten persistent zu gestalten, indem sie den Inhalt des Listenansichtssteuerelements beim Schließen von TuneTown in eine Datenträgerdatei schreiben und diese Inhalte beim nächsten Start von TuneTown wieder lesen. Ich verwende die .NET Framework Klassen StreamWriter und StreamReader (Member des System.IO-Namespace), um die Eingabe und Ausgabe von Textzeichenfolgen zu erleichtern.
      Die erforderlichen Änderungen sind in Abbildung 20 hervorgehoben. OnClosing ist eine virtuelle Methode, die von System.WinForms.Form geerbt wird und kurz vor dem Schließen eines Formulars aufgerufen wird. Die OnClosing-Implementierung von MainForm erstellt eine Textdatei namens TuneTownData.ttd im Anwendungsdatenpfad des lokalen Benutzers (SystemInformation.GetFolderPath (SpecialFolder.LocalApplicationData)). Anschließend wird der Text jedes Elements und Unterelements im Listenansichtssteuerelement in die Datei geschrieben. Beim nächsten Start von TuneTown öffnet die InitializeListView-Methode von MainForm die Datei, liest die Zeichenfolgen und schreibt sie zurück in die Listenansicht.
      Beachten Sie die Aufrufe der Close-Methoden der StreamWriter- und StreamReader-Objekte. Der Grund, warum ich diese Aufrufe einschloss, hat mit deterministischen und nicht deterministischen Zerstörung zu tun. Sprachen wie C++ verwenden deterministische Zerstörung, bei der Objekte zu genauen Zeitpunkten außerhalb des Gültigkeitsbereichs liegen (und zerstört werden). Die .NET-CLR, die einen Garbage Collector zum Freigeben von Ressourcen verwendet, verwendet jedoch nicht deterministische Zerstörung, was bedeutet, dass es keine Garantie gibt, wann (oder wenn) der Garbage Collector aktiviert wird. Normalerweise ist es Ihnen egal, wann die Garbage Collection ausgeführt wird. Wenn ein Objekt jedoch eine Nicht-Arbeitsspeicherressource wie z. B. ein Dateihandle kapselt, möchten Sie unbedingt, dass die Zerstörung deterministisch ist, da Sie möchten, dass dieses Dateihandle geschlossen wird, sobald es nicht mehr benötigt wird. Aus Gründen, auf die ich hier nicht eingehen werde, wird das Problem verschärft, wenn StreamWriter-Objekte beteiligt sind, da die Finalize-Methode einer StreamWriter-Methode, die aufgerufen wird, wenn ein StreamWriter-Objekt zerstört wird, keine Dateihandles zu schließen oder gepufferte Daten auf den Datenträger zu leeren. Wenn Sie Close nicht aufrufen, können Daten verloren gehen. Ich habe den zusätzlichen Schritt der Verwendung von finally-Blöcken unternommen, um TuneTown-Aufrufe von Close einzuschließen, um sicherzustellen, dass Close aufgerufen wird, auch nach inopportunen Ausnahmen.

Gedanken zum Teilen

      Es gibt noch mehr, was getan werden könnte, um TuneTown zu einer Anwendung mit vollem Funktionsumfang zu machen. Aber es ist an der Zeit, diese Diskussion zu einem Ende zu ziehen.
      Das Windows Forms Programmiermodell ist eine Wichtige für die kommenden Dinge. Es ist durchaus denkbar, dass zu einem zeitpunkt in der nicht allzu fernen Zukunft die überwiegende Mehrheit der Windows-basierten Programmierung auf .NET-Weise erfolgt. Wird sich die Branche dieser Vision anschließen? Es ist zu früh, um es zu sagen, aber es gibt eine Sache, bei der Sie sicher sein können: Es wird ein interessantes paar Jahre werden.
Verwandte Artikel finden Sie unter:
https://msdn.microsoft.com/library/dotnet/cpguide/cpconoverviewofwinforms.htm
https://msdn.microsoft.com/msdnmag/issues/0900/framework/framework.asp
https://msdn.microsoft.com/msdnmag/issues/1000/framework2/framework2.asp
Hintergrundinformationen finden Sie unter:
https://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28000519
Jeff Prosise macht seinen Lebensunterhalt, Windows zu programmieren und anderen beizubringen, wie man dasselbe tut. Er ist auch Mitbegründer von Wintellect, einem führenden Entwicklertrainings- und Beratungsunternehmen. Um Jeff zu kontaktieren, senden Sie eine E-Mail an jeffpro@wintellect.com.

Aus der Februar-Ausgabe 2001 des MSDN Magazine