Programmieren in C#: Einführung


Kapitel 5: Komponenten


Inhaltsverzeichnis

Dieses Buch ist unter einer Creative Commons-Lizenz lizensiert.


5.1 Allgemeines

Einfache Wiederverwendung von Code

Komponenten stellen die nächst größere Einheit über den Klassen in den Organisationsstrukturen einer Software dar. Während Klassen so geformt werden, dass sie Objekten aus der Wirklichkeit entsprechen, steht bei Komponenten die Wiederverwendbarkeit im Vordergrund. Dazu bieten Komponenten eine einheitliche Schnittstelle an, die sicherstellt, dass Komponenten - egal, welcher Art - auf die gleiche Weise angesprochen und verarbeitet werden können. Dies ermöglicht es, Werkzeuge zu erstellen, die die Entwicklung von Anwendungen vereinfachen, indem nicht mehr Code geschrieben wird, sondern ähnlich einem Baukastensystem Komponenten zusammengesteckt werden.

Visual C# bietet Editoren an, die die Schnittstellen von Komponenten kennen und daher das Arbeiten mit Komponenten unterstützen. So ist es zum Beispiel möglich, per Mausklick Komponenten einer Anwendung hinzuzufügen und sie zu konfigurieren, ohne eigenen Code schreiben zu müssen. Die Editoren müssen dabei gar nicht verstehen, was die Komponenten im Detail machen und welche Funktionen sie genau zur Verfügung stellen. Aufgrund der einheitlichen Schnittstelle sind die Editoren in der Lage, mit jeder beliebigen Komponente umzugehen.

In diesem Kapitel werden Sie erstmals .NET-Anwendungen mit einer grafischen Benutzeroberfläche entwicklen. Denn Windows-Anwendungen basieren auf Komponenten. Visual C# stellt mit dem Ansicht-Designer außerdem einen Editor bereit, mit dem Sie Fenster aus Komponenten zusammenbauen können. Wie dies im Detail funktioniert, lernen Sie in diesem Kapitel kennen.


5.2 Entwicklungsprozess

Vorgehensweise zur Entwicklung von Komponenten

Die Idee, die hinter Komponenten steckt, ist es, aufgrund einheitlicher Schnittstellen die Wiederverwendung von Code auf eine einfache Art und Weise zu ermöglichen. Das wird üblicherweise dadurch erreicht, indem Werkzeuge zur Verfügung gestellt werden, die die einheitlichen Schnittstellen kennen und das Arbeiten mit Komponenten vereinfachen.

Während Klassen ebenfalls ein Instrument sind, das die Wiederverwendung unterstützt, müssen Klassen in Quellcode vorliegen. Komponenten hingegen gestatten die Wiederverwendung in Binärform. Sie müssen weder Zugriff auf den Quellcode von Komponenten haben noch müssen diese Komponenten in der gleichen Programmiersprache entwickelt sein, die Sie verwenden. Komponenten bieten sich daher auch an, wenn Sie Klassenbibliotheken erstellen und kommerziell vertreiben möchten. Immerhin müssen Sie den Quellcode, auf dem Ihre Komponenten basieren, nicht veröffentlichen.

Container-Modell mit Sites und Komponenten

In Visual C# existieren Editoren, die es gestatten, Funktionen, die als Komponenten implementiert sind, per Mausklick einer Anwendung hinzuzufügen, ohne eigenen Code schreiben zu müssen. Damit das funktioniert, müssen die entsprechenden Komponenten eine einheitliche Schnittstelle anbieten, über die die Editoren die Komponenten ansprechen können. Diese Schnittstelle ist im .NET-Framework als Interface IComponent definiert.

Wenn Sie sich die Dokumentation von IComponent ansehen, stellen Sie fest, dass dieses Interface nur eine Methode und eine Eigenschaft definiert. Es wird darüberhinaus ein Ereignis definiert. Ereignisse lernen Sie aber erst im nächsten Kapitel kennen.

Klassen, die IComponent implementieren, müssen eine Methode IDispose() definieren. Das ist notwendig, weil IComponent vom Interface IDispose abgeleitet ist. Damit soll sichergestellt sein, dass Komponenten explizit native Ressourcen freigeben können, sollten Komponenten derartige Ressourcen verwenden.

Die Eigenschaft, die von IComponent vorgegeben wird, heißt Site. Es handelt sich dabei um eine Eigenschaft, die sowohl gelesen als auch geschrieben werden kann. Sie gibt an, zu welcher Site eine Komponente zählt. Sites werden von Containern angeboten, die Komponenten in sich aufnehmen können. Während Sites den Datentyp ISite haben, sind Container vom Typ IContainer.

Wenn Sie eine Komponente erstellen wollen, können Sie eine Klasse definieren, die das Interface IComponent implementiert. Sie können aber auch - und das ist die empfohlene Vorgehensweise - eine Klasse von Component ableiten.

Im Folgenden soll nun eine Komponente erstellt werden, mit der Favoriten verwaltet werden können. Da Komponenten keine Programme sind, die ausgeführt werden können, sondern der Wiederverwendung dienen, werden sie üblicherweise in Klassenbibliotheken bereitgestellt. Wenn Sie in Visual C# ein neues Projekt erstellen, sollten Sie daher die Vorlage Klassenbibliothek wählen, wenn Sie Komponenten entwickeln.

using System; 
using System.ComponentModel; 

public class FavoriteManager : Component 
{ 
  Favorite[] favs; 

  public void Add(string name, string url) 
  { 
    if (favs == null) 
    { 
      favs = new Favorite[] { new Favorite(name, new Uri(url)) }; 
    } 
    else 
    { 
      Favorite[] favs2 = new Favorite[favs.Length + 1]; 
      Array.Copy(favs, favs2, favs.Length); 
      favs2[favs.Length] = new Favorite(name, new Uri(url)); 
      favs = favs2; 
    } 
  } 
} 

Die obige Klasse FavoriteManager soll eine Komponente sein, mit der Favoriten verwaltet werden können. Dazu bietet sie eine Methode Add() an, der zwei Parameter vom Typ string übergeben werden können, um einen Favoriten zum Manager hinzuzufügen. Damit die Klasse außerdem eine Komponente ist, wird sie von Component abgeleitet. Da diese Klasse im Namensraum System.ComponentModel definiert ist, werden alle Klassen in diesem Namensraum über die using-Deklaration bekannt gemacht.

Projektmappen-Explorer in Visual C# mit zwei Dateien Favorite.cs und FavoriteManager.cs

Die Klasse FavoriteManager bedient sich der Klasse Favorite, die in den vorherigen Kapiteln entwickelt wurde. Projekte, in denen mehrere Klassen verwendet werden, werden typischerweise so organisiert, dass jede Klasse in ihrer eigenen Datei liegt, die genauso heißt wie die Klasse. So könnte obige Klasse FavoriteManager in einer Datei FavoriteManager.cs gespeichert sein, während die Klasse Favorite in einer anderen Datei Favorite.cs gespeichert ist.

Die erste Version des Favoriten-Managers ist sehr einfach gestrickt: FavoriteManager bietet lediglich eine einzige Methode Add() an, um neue Favoriten im Manager abzulegen. Die beiden Strings, die als Parameter an diese Methode übergeben werden, werden verwendet, um ein Objekt vom Typ Favorite zu erstellen und dieses im Array favs zu speichern.

Wenn ein Objekt vom Typ FavoriteManager erstellt wird, ist das Array favs auf null gesetzt. Erst dann, wenn über Add() ein Favorit abgelegt wird, wird ein Array mit new erstellt und in der Referenzvariablen favs verankert. Da bei einem zweiten Aufruf von Add() das nun existierende Array verändert werden muss, um den neuen Favorit hinzuzufügen, muss Add() jeweils etwas anderes tun - je nachdem, ob die Methode zum ersten Mal aufgerufen wird oder nicht.

C# bietet mit der if-else-Kontrollstruktur ein Werkzeug an, um in Abhängigkeit einer Bedingung unterschiedlichen Code auszuführen. Die entsprechende Bedingung, die überprüft werden soll, wird dabei in runden Klammern hinter if angegeben. Ist das Ergebnis der Bedingung true, wird der Anweisungsblock ausgeführt, der hinter dem if folgt. Ist die Bedingung false, wird der Anweisungsblock hinter dem else ausgeführt.

Beachten Sie, dass ein else optional ist und weggelassen werden kann. Wenn Sie keinen bestimmten Code ausführen möchten, wenn eine Bedingung false ergibt, brauchen Sie auch kein else angeben.

Obige Methode Add() überprüft, ob die Referenzvariable favs null ist. Ist sie das, ist klar, dass Add() erstmalig aufgerufen wird und deswegen ein neues Array erstellt werden muss, in dem der Favorit gespeichert werden soll. Ist sie das nicht, muss im Anweisungsblock hinter else ein neues Array erstellt werden, das einen Speicherplatz mehr als das Array favs bietet. Es müssen dann alle Favoriten in favs in das neue Array hinüberkopiert werden. In dem zusätzlichen Speicherplatz kann dann der neue Favorit gespeichert werden.

Um Elemente von einem Array in ein anderes zu kopieren, kann die statische Methode Copy() der Klasse Array verwendet werden. Diese erwartet als ersten Parameter eine Referenzvariable des Arrays, von dem Elemente kopiert werden soll. Das Array, in das Elemente kopiert werden sollen, muss als zweiter Parameter angegeben werden. Der dritte Parameter gibt an, wie viele Elemente kopiert werden sollen.

Wenn die Klasse FavoriteManager in einer Klassenbibliothek definiert wird, um sie auf diese Weise Anwendungen zur Verfügung zu stellen, muss vor dem Schlüsselwort class das Zugriffsattribut public angegeben werden. Denn erst das macht es möglich, dass eine Klasse außerhalb der Datei verwendet werden kann, in der sie definiert ist.

Im Folgenden sehen Sie der Vollständigkeit halber den Code der Klasse Favorite, wie sie von FavoriteManager verwendet wird.

using System; 
using System.Diagnostics; 

class Favorite 
{ 
  string name; 
  Uri url; 

  public Favorite() 
  { 
  } 

  public Favorite(string name, Uri url) 
  { 
    this.name = name; 
    this.url = url; 
  } 

  public string Name 
  { 
    get { return name; } 
    set { name = value; } 
  } 

  public Uri URL 
  { 
    get { return url; } 
    set { url = value; } 
  } 

  void Open() 
  { 
    Process.Start(url.ToString()); 
  } 
} 

Es ist nicht notwendig, das Zugriffsattribut public vor die Klassendefinition von Favorite zu setzen, da Anwendungen, die den Favoriten-Manager einsetzen werden, nicht auf die Klasse Favorite zugreifen. Die Klasse Favorite wird ausschließlich innerhalb der Klassenbibliothek verwendet. Sie können das auch explizit ausdrücken, indem Sie das Schlüsselwort internal vor class setzen. Das hat den gleichen Effekt wie wenn Sie kein Zugriffsattribut vor class angeben.

Wenn Sie den Favoriten-Manager in Visual C# in einer Klassenbibliothek entwickelt haben, können Sie Ihren Code nicht testen, indem Sie zum Beispiel auf F5 drücken. Da eine Klassenbibliothek keine Anwendung ist, kann sie nicht ausgeführt werden.

Klicken Sie im Menü Erstellen auf Projektmappe erstellen, um den Favoriten-Manager zu kompilieren. Wahlweise können Sie auch auf F6 drücken. Visual C# erstellt dann eine Datei, in der die Komponente des Favoriten-Managers zur Verfügung gestellt wird. Diese Datei hat die Endung dll und wird entweder im Unterverzeichnis bin\Release oder bin\Debug von Ihrem Projektverzeichnis erstellt. Sie können nun diese Datei zum Beispiel anderen Entwicklern zur Verfügung stellen, die Ihren Favoriten-Manager dann in ihren Programmen einsetzen können.


5.3 Komponenten-Eigenschaften

Komponenten konfigurieren

Während Sie nun wissen, wie Sie eine Komponente entwickeln, scheint der Favoriten-Manager bisher keine Vorteile gegenüber einer herkömlichen Klasse zu bieten. Immerhin würde der Favoriten-Manager auch dann funktionieren, wenn er nicht von Component abgeleitet wäre.

Komponenten können per Mausklick einer Anwendung hinzugefügt und konfiguriert werden, ohne Code schreiben zu müssen. Während der Favoriten-Manager bereits als Komponente vorliegt und - wie Sie noch sehen werden - tatsächlich per Mausklick einer Anwendung hinzugefügt werden kann, bietet er im Moment noch keine Eigenschaften an, über die er konfiguriert werden kann. Deswegen soll die Klasse FavoriteManager um eine entsprechende Eigenschaft erweitert werden, bevor Sie sehen werden, wie die Komponente eingesetzt werden kann.

Der Favoriten-Manager unterstützt die Verwaltung von Favoriten, die mit Add() hinzugefügt werden können. Wird er in einer Anwendung eingesetzt, können mit Hilfe dieser Komponente sehr einfach Favoriten gespeichert werden. Damit Entwickler, die die Komponente in ihren Programmen einsetzen wollen, jedoch Favoriten voreinstellen können, wird die Komponente im Folgenden um eine entsprechende Eigenschaft erweitert.

using System; 
using System.ComponentModel; 

public class FavoriteManager : Component 
{ 
  Favorite[] favs; 

  public void Add(string name, string url) 
  { 
    if (favs == null) 
    { 
      favs = new Favorite[] { new Favorite(name, new Uri(url)) }; 
    } 
    else 
    { 
      Favorite[] favs2 = new Favorite[favs.Length + 1]; 
      Array.Copy(favs, favs2, favs.Length); 
      favs2[favs.Length] = new Favorite(name, new Uri(url)); 
      favs = favs2; 
    } 
  } 

  public Favorite[] Favorites 
  { 
    set { favs = value; } 
    get { return favs; } 
  } 
} 

Der Komponente wurde nun eine Eigenschaft hinzugefügt, über die Entwickler im Favoriten-Manager Favoriten voreinstellen können. Wie Sie sehen handelt es sich bei dieser Eigenschaft um etwas, was Sie bereits kennen. In der Tat sind Komponenten-Eigenschaften nichts anderes als Eigenschaften einer Klasse.

Editoren, die das Arbeiten mit Komponenten unterstützen, greifen auf Eigenschaften zu und machen es Entwicklern möglich, die Eigenschaften zu verändern, ohne Code schreiben zu müssen. So bietet Visual C# ein sogenanntes Eigenschaftenfenster an, das Eigenschaften von Komponenten tabellenartig auflistet. Über dieses Eigenschaftenfenster können dann Komponenten-Eigenschaften gelesen und geschrieben werden - der entsprechende Code wird automatisch generiert. Indem der Klasse FavoriteManager nun eine Eigenschaft hinzugefügt wurde, können Entwickler im Favoriten-Manager auf einfache Art und Weise Favoriten voreinstellen.

Beachten Sie, dass Editoren üblicherweise ausschließlich Komponenten-Eigenschaften für Entwickler zugänglich machen. Methoden wie Add() stehen selbstverständlich weiterhin zur Verfügung und können aufgerufen werden. Dies ist jedoch etwas, was explizit geschehen muss. Code für Methodenaufrufe muss manuell geschrieben werden und kann - jedenfalls in allen bisherigen Versionen von Visual C# - nicht automatisch generiert werden. Eigenschaften machen daher die Wiederverwendung von Komponenten bedeutend einfacher als wenn eine Komponente ausschließlich Methoden definiert.


5.4 Ansicht-Designer

Anwendungen mit der Maus zusammenklicken

Wenn Sie eine Komponente entwickelt haben und sie in einer Klassenbibliothek Anwendungen zur Verfügung stellen, können Sie diese Komponente dank der speziellen Unterstützung in Visual C# sehr einfach einer Anwendung hinzufügen. Das trifft genaugenommen aber nur dann zu, wenn Sie eine Anwendung erstellen, die einen Container für Komponenten zur Verfügung stellt. Konsolenanwendungen, die bisher in diesem Buch für alle Beispiele verwendet wurden, stellen von Haus aus keinen Container zur Verfügung. .NET-Anwendungen mit grafischer Benutzeroberfläche besitzen jedoch einen derartigen Container.

Um den Favoriten-Manager einzusetzen, sollten Sie nun ein neues Projekt in Visual C# vom Typ einer Windows Forms-Anwendung erstellen. Wahlweise können Sie auch der Projektmappe, in der sich das Projekt mit dem Favoriten-Manager befindet, ein neues Projekt vom Typ einer Windows Forms-Anwendung hinzufügen. Das erleichtert die Entwicklung insofern als dass Sie Zugriff auf beide Projekte haben und bei Änderungen im Code nicht ständig das eine Projekt schließen müssen, um das andere zu öffnen.

Windows Forms-Anwendung mit Ansicht-Designer

Wenn Sie die Windows Forms-Anwendung erstellt haben - egal, ob in einer neuen Projektmappe oder als zweites Projekt in der Projektmappe des Favoriten-Managers - sehen Sie erstmals den Ansicht-Designer. Es handelt sich dabei um den Editor, der von Visual C# verwendet wird, um grafische Benutzeroberflächen zu erstellen.

Der Ansicht-Designer unterstützt das sogenannte Rapid Application Development. Darunter versteht man einen Entwicklungsprozess, in dem mit Hilfe spezieller Werkzeuge sehr schnell Code erzeugt werden kann, ohne dass Code vom Programmierer geschrieben werden muss. Visual C# unterstützt das Rapid Application Development durch den Ansicht-Designer. Es handelt sich dabei um ein Baukastensystem, das auf Komponenten basiert. Was immer Sie im Ansicht-Designer mit Komponenten machen, wird von Visual C# automatisch in Code umgesetzt.

Eine Windows Forms-Anwendung basiert wie eine Konsolenanwendung auch auf einer Klasse, die eine statische Methode Main() definiert. Innerhalb von Main() greifen Sie jedoch nicht mehr auf die Konsole zu, um Daten auszugeben oder einzulesen. Stattdessen fügt Visual C# Main() Code hinzu, wenn Sie eine Windows Forms-Anwendung entwickeln, um in Main() ein Objekt vom Typ einer Klasse Form1 zu erstellen.

Die Klasse Form1 ist von einer Klasse Form abgeleitet, die aus dem Namensraum System.Windows.Forms stammt. Die Klasse Form stellt die wichtigste Klasse dar, um typische Fenster anzuzeigen, wie Sie sie von Windows-Anwendungen kennen. Diese Fenster heißen im .NET-Framework Formulare, was den Namen der Klasse erklärt. Mit Form kann jedoch nun nicht nur erstmals eine grafische Benutzeroberfläche erstellt werden. Diese Klasse stellt auch einen Container für Komponenten dar.

Da Form1 aufgrund der Elternklasse Form Komponenten unterstützt, können Sie zwischen der Code-Ansicht und dem Ansicht-Designer wählen, wenn Sie Form1 bearbeiten möchten. So wird bei einem Doppelklick auf die entsprechende Datei Form1.cs standardmäßig der Ansicht-Designer geöffnet. Möchten Sie hingegen den Code sehen, auf dem Form1 basiert, können Sie die Code-Ansicht im Kontext-Menü auswählen, wenn Sie mit der rechten Maustaste auf die Datei Form1.cs klicken.

Verweis auf die Datei mit der Komponente des Favoriten-Managers

Weil der Ansicht-Designer automatisch Code zur Klasse Form1 hinzufügt, wenn Sie mit Komponenten im Ansicht-Designer arbeiten, Sie unter Umständen aber auch selbst in der Code-Ansicht eigenen Code schreiben möchten, muss Visual C# dafür sorgen, dass der vom Ansicht-Designer automatisch generierte Code mit Ihrem manuell geschriebenen Code nicht durcheinander kommt. Deswegen ist die Klasse Form1 in zwei Dateien definiert: Die Datei Form1.cs ist für Sie gedacht, die Datei Form1.Designer.cs für den Ansicht-Designer. Sie können aber auch diese Datei öffnen, indem Sie den Eintrag zur Datei Form1.cs im Projektmappen-Explorer öffnen und dann auf Form1.Designer.cs doppelklicken. Ein derartiges Aufteilen von Code einer Klasse in mehrere Dateien ist möglich, wenn das Schlüsselwort partial vor class angegeben wird - und zwar in allen Dateien, in denen die entsprechende Klasse definiert ist.

Um nun den Favoriten-Manager zu verwenden, müssen Sie dem Projekt zuerst einen Verweis auf die entsprechende Datei hinzufügen, in der der Favoriten-Manager implementiert ist. Im Menü Projekt finden Sie einen Eintrag Verweis hinzufügen.... Je nachdem, ob sich der Favoriten-Manager in einem Projekt in der gleichen Projektmappe befindet oder in einer anderen Projektmappe, müssen Sie die Registerkarte Projekte oder Durchsuchen verwenden: Während die Registerkarte Projekte Komponenten in Projekten auflistet, die sich in der gleichen Projektmappe befinden, können Sie über die Registerkarte Durchsuchen beliebige Dateien angeben, in denen sich Komponenten befinden. So können Sie zum Beispiel in das Unterverzeichnis bin\Release oder bin\Debug des Verzeichnisses wechseln, in dem sich das Projekt des Favoriten-Managers befindet, und die entsprechende dll-Datei auswählen.

Wenn Sie die Datei ausgewählt und hinzugefügt haben, die die Komponente des Favoriten-Managers enthält, finden Sie einen entsprechenden Verweis im Projektmappen-Explorer. Somit kann nun auf Code zugegriffen werden, der von der Klassenbibliothek zur Verfügung gestellt wird - also auch auf den Favoriten-Manager.

Öffnen Sie im nächsten Schritt die Toolbox. Wenn keine entsprechende Leiste auf der linken Seite von Visual C# sichtbar ist, können Sie sie über das Menü Ansicht und dann über Toolbox einblenden.

Die Toolbox zeigt eine Übersicht über sämtliche .NET-Komponenten, auf die Sie Zugriff haben und die Sie in Ihrer Anwendung verwenden können. So enthält diese Übersicht zum Beispiel zahlreiche Steuerelemente, die Sie verwenden können, um Daten in Fenstern anzuzeigen oder Eingaben vom Anwender entgegenzunehmen. Weil im .NET-Framework sehr viele Komponenten definiert sind, sind sie üblicherweise Kategorien zugeordnet, um den Überblick zu erleichtern.

Nachdem Sie einen Verweis auf Ihre Klassenbibliothek, die die Komponente für den Favoriten-Manager enthält, Ihrem Projekt hinzugefügt haben, sollte der Favoriten-Manager ebenfalls in der Toolbox erscheinen. Da für den Favoriten-Manager keine Kategorie angegeben wurde, wird er unter anderem unter Allgemein angezeigt.

Eigenschaftenfenster des Favoriten-Managers

Klicken Sie nun auf das Symbol des Favoriten-Managers und ziehen Sie es hinüber auf das Formular, das im Ansicht-Designer angezeigt wird. Daraufhin erscheint eine Leiste am unteren Rand des Ansicht-Designers, in dem das Symbol des Favoriten-Managers angezeigt wird. Neben dem Symbol steht die Bezeichnung favoriteManager1.

Indem Sie die entsprechende Komponente mit der Maus dem Formular hinzugefügt haben, wurde von Visual C# Code generiert. Im entsprechenden Code wird die Komponente instantiiert und in der Referenzvariablen favoriteManager1 verankert. Ab sofort kennt das Formular also einen Favoriten-Manager und kann mit ihm arbeiten.

Da der Favoriten-Manager eine Eigenschaft Favorites anbietet, um Favoriten voreinzustellen, kann über das Eigenschaftenfenster auf genau diese Eigenschaft zugegriffen werden. Sollte das Eigenschaftenfenster nicht sichtbar sein, können Sie es über das Menü Ansicht einblenden.

Visual Studio bietet einen Favorite-Auflistungs-Editor an, über den Sie Favoriten eingeben können. Das funktioniert alles automatisch, ohne dass Sie irgendetwas programmieren müssen. Die einzige Voraussetzung ist, dass die Klasse Favorite einen Standardkonstruktor besitzt und sie Eigenschaften anbietet, über die dann ein Objekt vom Typ Favorite verändert werden kann. Da in der Klasse Favorite zwei Eigenschaften Name und URL definiert wurden, sind die Voraussetzungen erfüllt, um über das Eigenschaftenfenster des Ansicht-Designers Favoriten voreinzustellen.

Wenn Sie sich den Code anschauen, den Visual C# automatisch generiert, sehen Sie zwar, dass tatsächlich der Favoriten-Manager eingesetzt wird. Wenn Sie die Windows Forms-Anwendung aber ausführen, wird ein leeres Fenster angezeigt. Denn der Favoriten-Manager selbst hat keine grafische Benutzeroberfläche. Der Favoriten-Manager soll daher im Folgenden von einer Komponente zu einem Steuerelement mit grafischer Benutzeroberfläche umgebaut werden.


5.5 Steuerelemente

Komponenten mit grafischer Benutzeroberfläche

Neben Komponenten wie dem in diesem Kapitel entwickelten Favoriten-Manager, die Anwendungen bestimmte Dienste anbieten, gibt es eine Vielzahl von Komponenten, die grafische Benutzeroberflächen haben. Diese Komponenten werden als Steuerelemente bezeichnet. Es handelt sich hierbei um Klassen, die von Control abgeleitet sind - eine Klasse aus dem Namensraum System.Windows.Forms, die ihrerseits von Component abgeleitet ist. Somit sind alle Steuerelemente auch immer Komponenten und können im Ansicht-Designer bearbeitet werden.

Das .NET-Framework stellt eine Vielzahl an Steuerelementen zur Verfügung, um grafische Benutzeroberflächen zu entwickeln. Wenn Sie zum Beispiel einen Blick in die Kategorie der allgemeinen Steuerelemente in der Toolbox werfen, sehen Sie zahlreiche Steuerelemente, die Sie aus vielen Windows-Anwendungen kennen.

Fügen Sie im Ansicht-Designer Ihrem Fenster das Steuerelement MenuStrip hinzu, das Sie unter Menüs und Symbolleisten finden. Dieses Steuerelement stellt eine Menüleiste dar. Wenn Sie diese Menüleiste im Fenster auswählen, wird ein Symbol eingeblendet, über das Sie der Menüleiste weitere Steuerelemente hinzufügen können. Klicken Sie auf das Symbol und dann auf MenuItem. Daraufhin wird in der Menüleiste ein Menüeintrag angezeigt.

Wenn die Menüleiste oder der Menüeintrag ausgewählt ist, können sie diese Steuerelemente über das Eigenschaftenfenster konfigurieren - so wie Sie vorher den Favoriten-Manager konfigurieren konnten. Wenn Sie einen Blick auf die Eigenschaften der Menüleiste werfen, stellen Sie fest, dass dieses Steuerelement wesentlich mehr Eigenschaften anbietet als der Favoriten-Manager.

Klicken Sie nun auf den Menüeintrag, den Sie der Menüleiste hinzugefügt hatten, und setzen Sie die Eigenschaft Text auf Als Favorit speichern. Im Ansicht-Designer ändert sich daraufhin die Beschriftung des Menüeintrags.

Es wäre schön, wenn der Favoriten-Manager ebenfalls eine grafische Benutzeroberfläche hätte. So könnten zum Beispiel alle Favoriten in einer Liste dargestellt werden anstatt unsichtbar für den Anwender innerhalb der Anwendung gespeichert zu werden. Dazu wird der Favoriten-Manager im Folgenden von einer Komponente in ein Steuerelement umgewandelt. Denn nur dann kann er tatsächlich mit einer eigenen grafischen Benutzeroberfläche angezeigt werden.

using System; 
using System.Windows.Forms; 

public class FavoriteManager : UserControl 
{ 
  private ListBox listBox1; 
  Favorite[] favs; 

  public FavoriteManager() 
  { 
    InitializeComponent(); 
    listBox1.DisplayMember = "Name"; 
  } 

  public void Add(string name, string url) 
  { 
    if (favs == null) 
    { 
      favs = new Favorite[] { new Favorite(name, new Uri(url)) }; 
      listBox1.DataSource = favs; 
    } 
    else 
    { 
      Favorite[] favs2 = new Favorite[favs.Length + 1]; 
      Array.Copy(favs, favs2, favs.Length); 
      favs2[favs.Length] = new Favorite(name, new Uri(url)); 
      favs = favs2; 
      listBox1.DataSource = favs; 
    } 
  } 

  public Favorite[] Favorites 
  { 
    set 
    { 
      favs = value; 
      listBox1.DataSource = favs; 
    } 

    get { return favs; } 
  } 

  private void InitializeComponent() 
  { 
    this.listBox1 = new System.Windows.Forms.ListBox(); 
    this.SuspendLayout(); 
    // 
    // listBox1 
    // 
    this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill; 
    this.listBox1.FormattingEnabled = true; 
    this.listBox1.Location = new System.Drawing.Point(0, 0); 
    this.listBox1.Name = "listBox"; 
    this.listBox1.Size = new System.Drawing.Size(150, 147); 
    this.listBox1.TabIndex = 0; 
    // 
    // FavoriteManager 
    // 
    this.Controls.Add(this.listBox1); 
    this.Name = "FavoriteManager"; 
    this.ResumeLayout(false); 
  } 
} 

Die Klasse FavoriteManager wird nun anstatt von Component von UserControl abgeleitet. UserControl steht seinerseits in einer Vererbungslinie mit Control - der Klasse, von der alle Steuerelemente abgeleitet sein müssen.

Der Grund, warum FavoriteManager nicht direkt von Control abgeleitet wird, ist, dass UserControl die Entwicklung von Steuerelementen erleichtert. Während Steuerelemente, die von Control abgeleitet werden, tatsächlich ihre eigene Benutzeroberfläche zeichnen müssen, können Steuerelemente, deren Elternklasse UserControl ist, andere existierende Steuerelemente wiederverwenden. So soll auch für den FavoriteManager ein existierendes Steuerelement wiederverwendet werden, das im .NET-Framework zur Verfügung gestellt wird: Mit der Liste vom Typ ListBox aus dem Namensraum System.Windows.Forms sollen im Favoriten-Manager gespeicherte Favoriten angezeigt werden.

So wie der Favoriten-Manager in einer Klassenbibliothek anderen Anwendungen zur Verfügung gestellt wird, sind auch alle Klassen aus dem .NET-Framework in unterschiedlichen Klassenbibliotheken definiert. Je nachdem, auf welche Klasse Sie zugreifen möchten, müssen Sie daher erst einen Verweis auf die entsprechende Datei Ihrem Projekt hinzufügen. So befinden sich alle Klassen, die wie ListBox Steuerelemente für grafische Benutzeroberflächen darstellen, in einer Datei System.Windows.Forms.dll. Überprüfen Sie im Projektmappen-Explorer, ob das Projekt des Favoriten-Managers bereits einen Verweis auf diese Datei besitzt. Falls nicht, müssen Sie über Projekt und Verweis hinzufügen einen Verweis erstellen. In diesem Fall müssen Sie sehr wahrscheinlich auch einen Verweis auf eine Datei System.Drawing.dll hinzufügen, da der von Visual C# automatisch generierte Code unter anderem auf Klassen aus dieser Datei zugreift.

Wenn Sie die Elternklasse von FavoriteManager von Component in UserControl ändern, können Sie den Favoriten-Manager im Ansicht-Designer öffnen. Dort wird die Oberfläche des Favoriten-Managers als graue Box ohne Titelleiste oder Rahmen angezeigt. Da der Favoriten-Manager ein Steuerelement sein soll, das später in einem Formular eingesetzt werden soll, reicht die graue Box als Malfläche aus.

Fügen Sie nun im Ansicht-Designer wie gewohnt mit der Maus eine Liste aus der Toolbox dem Favoriten-Manager hinzu. Sie finden die Liste unter den allgemeinen Steuerelementen.

Wenn Sie die Liste hinzugefügt haben, können Sie das Steuerelement ebenfalls wie gewohnt über das Eigenschaftenfenster konfigurieren. Setzen Sie zum Beispiel die Eigenschaft Dock auf Fill, damit die Liste die Fläche des Favoriten-Managers vollständig ausfüllt.

Weil die Liste in irgendeiner Weise die Favoriten anzeigen soll, die vom Favoriten-Manager gespeichert werden, muss sie mit dem Array favs verbunden werden. Das geschieht über die Eigenschaft DataSource der Liste. Die Zuweisung von favs an DataSource muss jedoch im Code vorgenommen werden. So nützlich der Ansicht-Designer ist - um das Schreiben von C# werden Sie nicht gänzlich umhin kommen.

Sie können DataSource jedes beliebige Objekt zuweisen, das auf einer Klasse basiert, die entweder das Interface IList oder IListSource implementiert. Diese Interfaces verlangen, dass sich ein Objekt wie eine Liste verhält. Eine Klasse, die IList implementiert, ist Array. Deswegen kann das Array favs der Eigenschaft DataSource zugewiesen werden.

Wenn Sie sich die Datei FavoriteManager.cs ansehen, nachdem Sie im Ansicht-Designer gearbeitet haben, stellen Sie fest, dass Visual C# eine Methode InitializeComponent() hinzugefügt hat. In dieser Methode generiert Visual C# automatisch Code, der dem entspricht, was Sie im Ansicht-Designer tun. Sie sollten daher die Methode InitializeComponent() niemals manuell ändern.

Während Visual C# InitializeComponent() automatisch definiert, wird diese Methode bisher nirgendwo aufgerufen. Damit der Favoriten-Manager tatsächlich als sichtbares Steuerelement erscheint, müssen Sie daher einen Konstruktor definieren, in dem Sie InitializeComponent() aufrufen. So ist sichergestellt, dass Programme, die sich des Favoriten-Managers bedienen, eine grafische Benutzerschnittstelle für diese Komponente erhalten.

Wie Sie anhand des obigen Quellcodes sehen, wird im Konstruktor nicht nur InitializeComponent() aufgerufen. Es wird darüberhinaus auf die Eigenschaft DisplayMember der Liste zugegriffen, um ihr den Namen einer Eigenschaften der Klasse Favorite zuzuweisen. Das ist notwendig, weil das Array favs Objekte vom Typ Favorite speichert, die Liste aus dem .NET-Framework aber diese Klasse nicht kennt. Damit die Liste weiß, was sie mit derartigen Objekten zu tun hat und was sie genau in Listeneinträgen anzeigen soll, wird ihr der Name der Eigenschaft gegeben, über den sie an den Werte gelangt, die in der Liste angezeigt werden sollen.

Windows Forms-Anwendung mit Favoriten-Manager

Beachten Sie, dass die Eigenschaft DisplayMember der Liste im Konstruktor von FavoriteManager hinter dem Aufruf von InitializeComponent() gesetzt wird. Das ist notwendig, weil die Liste erst in InitializeComponent() erstellt wird.

Wechseln Sie zurück zum Projekt mit der Windows Forms-Anwendung, um den überarbeiteten Favoriten-Manager einzusetzen. Entfernen Sie die Komponente, die Sie zuvor dem Formular hinzugefügt haben. Sollte kein entsprechendes Symbol mit der Beschriftung favoriteManager1 angezeigt werden, liegt das daran, dass Visual C# durcheinander kam. Denn der Favoriten-Manager ist auf einmal keine Komponente mehr, sondern ein Steuerelement. In so einem Fall müssen Sie den Code, den Visual C# automatisch in InitializeComponent() generiert hat, manuell ändern. Öffnen Sie die Datei Form1.Designer.cs und entfernen Sie alle Zeilen in InitializeComponent(), die sich auf den Favoriten-Manager beziehen. Nehmen Sie möglichst keine anderen Änderungen vor, damit der Ansicht-Designer von Visual C# den Code in InitializeComponent() richtig interpretieren kann.

Wenn Sie das Formular bereinigt haben, ziehen Sie das Steuerelement des Favoriten-Managers von der Toolbox auf das Formular. Es erscheint daraufhin ein Listenelement, das im Formular positioniert werden kann: Der Favoriten-Manager hat nun eine eigene grafische Benutzeroberfläche.

Wie üblich können Sie die Komponente über das Eigenschaftenfenster konfigurieren. Setzen Sie zum Beispiel die Eigenschaft Dock auf Left, um den Favoriten-Manager auf der linken Seite des Fensters anzudocken.

Während die Eigenschaft Dock in der Klasse Control definiert ist und somit von allen Steuerelementen zur Verfügung gestellt wird, bietet der Favoriten-Manager eine Eigenschaft Favorites an, über die Favoriten voreingestellt werden können. Es handelt sich dabei um die in der Klasse FavoriteManager definierte Eigenschaft, die ebenfalls im Eigenschaftenfenster angezeigt wird. Sie können nun auf diese Weise einen Favoriten voreinstellen. Fügen Sie einen beliebigen Favoriten hinzu und führen Sie die Windows Forms-Anwendung dann aus. Wenn Sie alles richtig gemacht haben, sollte ein Fenster mit einer Liste erscheinen, die die Namen der von Ihnen voreingestellten Favoriten enthält.


5.6 COM-Komponenten

Alte COM-Komponenten in neuem Gewand

Im Einführungskapitel haben Sie erfahren, dass .NET eine Vorgängertechnologie hat, die COM heißt. Mit COM haben Microsoft und unzählige andere Firmen Komponenten entwickelt, die auf einfache Art und Weise - jedenfalls so einfach, wie das mit COM möglich war - wiederverwendbar waren. Da COM eine wesentlich ältere Technologie als .NET ist, sind im Laufe der Zeit sehr viele COM-Komponenten entwickelt worden. Um von diesen COM-Komponenten auch in der .NET-Welt zu profitieren, hat Microsoft eine Technologie namens COM-Interop entwickelt, die den Zugriff auf COM-Komponenten von .NET-Anwendungen aus erlaubt - und andersrum.

Dialogfenster zur Auswahl von Steuerelementen

Eine prominente COM-Komponente, die im Folgenden verwendet werden soll, ist der Microsoft Web Browser. Es handelt sich hierbei um die COM-Komponente, auf der der Internet Explorer basiert. Fast die gesamte Funktionalität dieses Browsers ist über eine COM-Komponente wiederverwendbar. So kann mit Hilfe dieser Komponente ein eigener Browser sehr einfach entwickelt werden, der genauso leistungsfähig ist wie der Internet Explorer, was die Darstellung von Webseiten betrifft.

Der Microsoft Web Browser ist eine COM-Komponente mit eigener grafischer Benutzeroberfläche. Er kann daher ähnlich wie .NET-Steuerelemente mit der Maus von der Toolbox auf ein Formular gezogen werden. So wie .NET-Komponenten ist es außerdem möglich, COM-Komponenten über das Eigenschaftenfenster zu konfigurieren.

Die Toolbox in Visual C# zeigt standardmäßig keine COM-Komponenten an. Sie müssen COM-Komponenten daher erst zur Toolbox hinzufügen, um sie von der Toolbox auf ein Formular ziehen zu können. Öffnen Sie dazu das Kontextmenü der Toolbox, indem Sie mit der rechten Maus auf diese klicken, und wählen Sie Elemente auswählen.... Suchen Sie dann unter den COM-Steuerelementen nach dem Microsoft Web Browser und aktivieren Sie ihn per Mausklick auf das Kontrollkästchen. Daraufhin erscheint die COM-Komponente des Microsoft Web Browsers in der Toolbox.

Ziehen Sie nun mit der Maus das Steuerelement des Microsoft Web Browsers auf das Formular im Ansicht-Designer. Visual C# generiert automatisch Code, um die COM-Komponente in Ihrer .NET-Anwendung einzufügen. Die Wiederverwendung von Komponenten, die auf COM basieren, ist ähnlich einfach wie die von .NET-Komponenten.

Sie können den Microsoft Web Browser nun ebenfalls über das Eigenschaftenfenster konfigurieren. Setzen Sie zum Beispiel die Eigenschaft Dock auf Fill, damit das Steuerelement das gesamte Fenster füllt. Wird die Größe des Fensters vom Anwender geändert, wächst das Steuerelement automatisch mit.

using System; 
using System.Windows.Forms; 

public partial class Form1 : Form 
{ 
  public Form1() 
  { 
    InitializeComponent(); 
    axWebBrowser1.Navigate("http://www.highscore.de/"); 
  } 
} 

Der Microsoft Web Browser bietet eine Methode Navigate() an, der eine Adresse als String übergeben werden kann. Rufen Sie diese Methode mit einer beliebigen Adresse im Konstruktor von Form1 auf und führen Sie Ihr Programm aus, um zu testen, ob tatsächlich die entsprechende Webseite angezeigt wird.

Windows Forms-Anwendung mit Favorite-Manager und dem Microsoft Web Browser

Wie Sie sehen ähnelt Ihre Windows Forms-Anwendung einem Browser. Es wird zwar zum Anzeigen von Webseiten die COM-Komponente des Internet Explorers verwendet. Dafür steht ein neuer Favoriten-Manager zur Verfügung.

Selbstverständlich ist der Browser aber noch nicht komplett. So wird zwar auf der linken Seite der Favoriten-Manager angezeigt, nur passiert nichts, wenn man auf einen Eintrag klickt. Während der Favoriten-Manager außerdem eine Methode Add() anbietet, um Favoriten zu speichern, passiert ebenfalls nichts, wenn man auf den entsprechenden Menüeintrag Als Favorit speichern klickt.

Bevor Sie im Kapitel 6, Ereignisse lernen, was Ereignisse sind und wie man mit ihnen auf Mausklicks reagiert, werden Sie in den folgenden Aufgaben die COM-Komponente des Microsoft Web Browsers durch eine entsprechende .NET-Komponente ersetzen. Weil ein Steuerelement zum Anzeigen von Webseiten so wichtig ist, stellt Microsoft im .NET-Framework ein entsprechendes .NET-Steuerelement bereit. Sie finden dieses Steuerelement, das einfach nur WebBrowser heißt, unter den allgemeinen Steuerlementen in der Toolbox. Insofern ist es nicht notwendig, zum Anzeigen von Webseiten auf eine COM-Komponente zuzugreifen. Sie haben zwar nun gesehen, wie einfach das ist. Mit dem WebBrowser-Steuerelement aus dem .NET-Framework können Sie jedoch in der .NET-Welt bleiben.


5.7 Zusammenfassung

.NET-Anwendungen schneller entwickeln mit Komponenten

Während Sie .NET-Anwendungen auch ohne Komponenten entwickeln können, spielen diese eine entscheidende Rolle, um .NET-Anwendungen schneller zu entwickeln. Da die Entwicklung grafischer Benutzeroberflächen mit Hilfe des Ansicht-Designers wesentlich schneller ist als den notwendigen Code selbst zu schreiben, werden Sie Komponenten automatisch verwenden. Da außerdem unzählige COM-Komponenten aus der Zeit vor dem .NET-Framework existieren, ist es gut zu wissen, dass diese Komponenten in .NET-Anwendungen wiederverwendet werden können, ohne sie für das .NET-Framework neu entwickeln zu müssen.


5.8 Aufgaben

Übung macht den Meister

Sie können die Lösungen zu allen Aufgaben in diesem Buch als ZIP-Datei erwerben.

  1. Entfernen Sie aus der im Abschnitt 5.6, „COM-Komponenten“ entwickelten Anwendung das COM-Steuerelement für den Microsoft Web Browser und fügen Sie stattdessen das entsprechende .NET-Steuerelement WebBrowser ein. Formatieren Sie das .NET-Steuerelement über das Eigenschaftenfenster und testen Sie es, indem beim Start der Anwendung automatisch eine Webseite aufgerufen wird und sich die Größe des Steuerelements verändert, wenn Sie das Fenster vergrößern oder verkleinern.

    Wenn Sie die COM-Komponente des Microsoft Web Browsers im Ansicht-Designer entfernen, erstellen Sie zum Test die Anwendung. Das hilft Ihnen zu erkennen, ob Sie zusätzlichen Code entfernen müssen, der auf den Microsoft Web Browser zugreift und nicht automatisch von Visual C# gelöscht wurde. Erst dann sollten Sie das .NET-Steuerelement WebBrowser dem Formular hinzufügen und formatieren.

  2. Fügen Sie dem Menü der Windows Forms-Anwendung aus Aufgabe 1 zwei neue Einträge namens Beenden und Info hinzu. Außerdem soll das Fenster eine Statusleiste am unteren Rand anzeigen. In dieser soll die Adresse der Webseite angezeigt werden, die beim Start der Anwendung automatisch geöffnet wird.

    Während Sie der Menüleiste per Mausklick neue Einträge hinzufügen können, müssen Sie für die Statusleiste ein neues Steuerelement von der Toolbox auf das Formular ziehen. Dabei kann es geschehen, dass die sich bereits auf dem Formular befindenden Steuerelemente des Favoriten-Managers oder des WebBrowsers die Statusleiste überlagern. Öffnen Sie dann die Dokumentgliederung über das Menü Ansicht und Weitere Fenster, um die Reihenfolge der Steuerelemente im Fenster zu ändern und zu verhindern, dass die Statusleiste überlagert wird.