Schnelles Umschalten von Bezügen in Excel

Um beispielsweise einen relativen Bezug auf die Zelle A1 in einen absoluten Bezug zu ändern, kann die Taste F4 gedrückt werden. A1 ändert sich dann in den absoluten Bezug $A$1. Drückt man nochmals F4 wird aus dem absoluten Bezug der gemischte Bezug A$1 (hier wird die Zeile beibehalten) und bei einem weiteren Betätigen von F4 der gemischte Bezug $A1 (die Spalte wird beibehalten). Drückt man abermals F4 hat man wieder einen relativen Bezug.

Das Grid-Steuerelement

Bei einem Grid handelt es sich um ein Steuerelement, mit dem sich Raster erzeugen lassen, dessen Bereich dynamisch ausgenutzt werden kann. Ändert sich die Größe des Grids, passen sich die Zellen automatisch entsprechend der Größenänderung an.

Mit dem nachfolgenden XAML-Code wird ein Grid-Steuerelement mit einem Raster von 4 Spalten und 3 Zeilen erzeugt. Wie man sieht, sind alle Zellen über das gesamte Grid gleichmäßig verteilt und damit gleich groß.

Fügt man nun eine weitere Spalte ein, werden die Zellen des Bereichs in der Breite entsprechend angepasst.

Um die automatische Größenveränderung in Aktion zu sehen, kann das Steuerelement im Browser betrachtet werden. Damit man die einzelnen Zellen auch sieht, setze ich das Attribut ShowGridLines für das Grid auf true

Nach dem Start der Anwendung präsentiert sich das Grid in meinem Browser wie in der nachfolgenden Darstellung gezeigt. Es umfasst 15 Zellen mit gleicher Größe.

Ändere ich nun die Größe meines Browserfensters, passt sich das Grid dynamisch an. Es sind weiterhin 15 gleich große Zellen zu sehen – jedoch sind die einzelnen Zellen jetzt kleiner.

Sofern Breite und Höhe des Grid nicht explizit definiert werden, erbt das Grid die Größe vom übergeordneten Element. Die Größe eines Grid kann mit Width und Height festgelegt werden.

Neben der Größe des Grid, lassen sich auch die Breite und Höhe der Spalten bzw. Zeilen festlegen. Bei der fixen Angabe in Pixeln verliert eine solche Zelle aber seine Dynamik, d.h. auch bei einer Größenänderung des Grid, behält die betreffende Zelle die festgelegte Größe bei.

In diesem Beispiel hat die erste Zeile eine Höhe von 20 Pixeln. Die restlichen Zeilen werden auf die verbleibende Höhe des Grids aufgeteilt. Da diese beiden Zeilen in der Größe dynamisch sind und bei beiden die Gewichtung 1 vorliegt (1*), sind auch beide gleichhoch. D.h. die Resthöhe wird durch 2 dividiert und somit ist jede Zeile der verbleibenden zwei Zeilen gleich hoch.

Gibt man jetzt beispielsweise der dritten Zeile eine Gewichtung von 3 (3*), wird die restlich verfügbare Höhe durch 4 dividiert – dann erhält die Zeile 2 eine Höhe von Resthöhe/4 und Zeile 3 eine Höhe von Resthöhe/4*3. D.h. bei einer Gesamthöhe des Grid von 300 Pixeln sind die Zeilenhöhen wie folgt:

  • Zeile 1: 20 Pixel     à Resthöhe = 300 – 20 = 280
  • Zeile 2: 70 Pixel     à 280/4 = 70
  • Zeile 3: 210 Pixel     à (280/4) *3 = 210

Unter Umständen möchte man aber für bestimmte Zellen eventuell eine Minimal- oder Maximalgröße angeben. Damit lassen sich dann auch dynamische Zellen realisieren, bei denen eine bestimmte Größe nicht unter- bzw. überschritten wird.

Um nun Elemente in den einzelnen Zellen des Rasters unterzubringen, müssen die Attached Properties Column und Row des Grid verwendet werden. In dem nachfolgenden Beispiel positioniere ich einen Button in der dritten Spalte von Zeile 3.

Wie man im XAML-Code oben sieht verwende ich sowohl für Column als auch Row den Wert 2 – das liegt ganz einfach daran, dass beim Raster sowohl für Zeilen als auch für Spalten mit 0 begonnen wird. Die erste Zelle links oben befindet sich demnach in der Spalte 0, Zeile 0.

Für die Schalter wurden keine Größen angegeben und daher erben diese die Größe der Zelle in der sie platziert wurden. Bei Größenänderung des Grid werden die Schalter automatisch in ihrer Größe angepasst.

Wird für den Schalter eine Größenangabe gemacht, behält dieser auch bei Größenänderungen des Rasters die eingestellte Größe bei.

Wird beispielsweise nur die Breite festgelegt, wird die Höhe wieder in Abhängigkeit der Rasterzelle bei Größenänderungen angepasst – lediglich die Breite bleibt dann unverändert.

Die im Grid enthaltene Layoutdynamik bietet ganz tolle Möglichkeiten. Das nachfolgende Beispiel soll dies demonstrieren.

In diesem Beispiel enthält eine Zelle des Rasters sogar ein weiteres Grid, bestehend aus 2 Zeilen und 2 Spalten.

Lässt man dieses Beispielprogramm laufen, sehen die roten Kreise und dir grünen Rechtecke ziemlich gleich aus (vorausgesetzt das Browserfenster hat die entsprechende Größe).

Bei Veränderung der Größe des Browserfensters erkennt man aber den Unterschied – bei den links angeordneten Elementen wird einfach abgeschnitten, wenn der Platz nicht ausreicht. Bei dem Polygon verhält es sich übrigens genauso. Wenn man sich die untere Abbildung anschaut könnte man glauben das Polygon wäre verkleinert – hier wurde aber auch einfach nur abgeschnitten. Schalter und Ellipse des 2×2 Grid passen sich wieder dynamisch an.

In einer Zelle können auch mehrere Elemente verwendet werden. In dem nachfolgenden Beispiel werden in Zelle 0,1 vier Rechtecke mit verschiedenen Farben definiert. Dabei wird über die Reihenfolge der Definitionen die Ausgabe festgelegt, d.h. die zuletzt definierten Elemente überlagern die vorherigen. Über Canvas.ZIndex kann dies beeinflusst werden. Wird beispielsweise für das gelbe Rechteck der ZIndex 1 verwendet, sind das schwarze und weiße Rechteck nicht mehr zu sehen, da das gelbe Rechteck darüber liegt.

Eine weitere Möglichkeit ist das Zusammenfassen von Spalten oder Zeilen durch die Attached Properties Grid.RowSpan und Grid.ColumnSpan. Damit lassen sich Zellen verbinden um entsprechende Ausgaben zu realisieren.

Im nachfolgenden der dazu notwendige XAML-Code. Die Definition der Rechtecke ist dabei etwas nach hinten verschoben, damit die Reihenfolge nicht über das ZIndex Attribut erfolgen muss.

Im Beispiel wurden lediglich 2 Zellen einer Zeile zusammengefasst. Eine Zusammenfassung kann sich aber auch über mehrere Spalten und Zeilen erstrecken.

Die Layoutmöglichkeiten des Grid bieten vielfältige Möglichkeiten zur Realisierung eigener Projekte. Es macht eine Menge Spaß mit dem Grid zu experimentieren und durch die Schachtelung von Elementen lässt sich einiges erreichen.

Rechte Maustaste und Kontextmenü in Silverlight 4

Klickt man in einer Silverlight Anwendung mit der rechten Maustaste, erscheint das Silverlight Kontextmenü, mit dem man die Silverlight-Konfiguration aufrufen kann.

Ab Silverlight 4 werden MouseRightButton… Ereignisse unterstützt.

Im nachfolgenden Beispiel, möchte ich einfach einmal das Silverlight Kontextmenü nicht mehr anzeigen lassen, wenn der Benutzer die rechte Maustaste drückt. Dazu registriere ich in der MainPage() Methode der MainPage.xaml.cs die Ereignisbehandlungsfunktion MyMouseRightButtonDown für das Ereignis MouseRightButtonDown. Innerhalb der Methode MyMouseRightButtonDown wird dann mit e.Handled = true festgelegt, dass das Ereignis bearbeitet wurde. Damit erscheint das Silverlight-Kontextmenü nicht mehr.

Als nächstes möchte ich nun, dass ein Kontextmenü erscheint, wenn ich die rechte Maustaste klicke.
Als erstes erstelle ich mir ein neues Silverlight Projekt und füge eine neues Element – und zwar ein Silverlight-Benutzersteuerelement – hinzu, dem ich den Namen ContexttEditControl gebe.

Das Benutzersteuerelement soll einfach aus einem Label und einer Textbox bestehen. Ziel ist es, dem Steuerelement ein Kontextmenü zuzuweisen. Der XAML-Code sieht folgendermaßen aus

Das ContextEditControl soll nun beim Anklicken des Eingabefeldes ein Kontextmenü anzeigen. Das Kontextmenü befindet sich in einem weiteren Steuerelement mit dem Namen ContextEditControlContext. Die XAML-Datei enthält die Definition des Kontextmenüs mit den einzelnen Menüpunkten Auschneiden, Kopieren und Einfügen.

Die Datei ContextEditControlContext.xaml.cs beinhaltet die Logik für das Kontextmenü. Als erstes wird eine neue Klasse ContextEditControlContextEventArgs von EventArgs abgeleitet. Diese nimmt den ausgewählten Menüeintrag als string auf (SelectedItem). Im Konstruktor wird ein EventHandler zur Auswahl eines Menüeintrages registriert – dieser ruft dann die Methode ctxList_SelectionChanged auf, die nichts anderes tut als den ausgewählten Menüeintrag als ctxSelected Event zu feuern. Wie man weiter unten sieht wird bei einem Klick mit der rechten Maustaste (s. ContextEditControl_MouseRightButtonDown) die entsprechende Methode im ContextEditControl aufgerufen.

Das Kontextmenü soll erscheinen, wenn der Benutzer die rechte Maustaste betätigt – dies entspricht dem Ereignis MouseRightButtonDown. Ferner soll das Kontextmenü geschlossen werden, wenn die linke Maustaste betätigt wurde oder das Control den Fokus verliert. Ich wechsele dazu auf ContextEditControl.xaml.cs und registriere hinter dem Methodenaufruf von InitializeComponent() entsprechende Ereignishandler.

Die Ereignisbehandlungsmethoden für LostFocus und MouseLeftButtonDown schließen lediglich das Kontextmenü.

Wird die rechte Maustaste gedrückt, wird über die Ereignisbehandlungsmethode für MouseRightButtonDown als erstes e.Handled auf true gesetzt – damit gilt das Ereignis als behandelt. Danach wird mittels CloseContextMenu() ein gegebenenfalls bereits geöffnetes Kontextmenü geschlossen und ein neues Popup erzeugt (für Popup wird der Namensraum System.Windows.Controls.Primitives benötigt). Dann wird eine Instanz für das Kontextmenü über das bereits oben gezeigte ContextEditControlContext erzeugt und ein Ereignishandler zur Behandlung der Auswahl in der Listbox des Kontextmenüs registriert, d.h. diese Methode wird aufgerufen, wenn der Benutzer eine Auswahl vorgenommen hat. In diesem Beispielprogramm erscheint dann einfach eine MessageBox mit der Auswahl (siehe Methode contextMenu_ctxSelected). Bis hierher erscheint das Kontextmenü noch nicht – dazu sind noch ein paar Kleinigkeiten zu erledigen. Über die MouseButtonEventArgs wird mit e.GetPosition(null) die Position des Mauszeigers ermittelt – diese Position entspricht dann der linken oberen Ecke des Kontextmenüs. Dann wird contextMenu als Kindelement (child) gesetzt, der Rahmen (Margin) definiert und zu guter Letzt das Kontextmenü über IsOpen=true angezeigt.

Mit dem nachfolgenden XAML-Code wird eine Eingabemaske mit zwei ContextEditControls und einem Schalter erzeugt

Lässt man die Anwendung laufen, kann in den Eingabefeldern mit der rechten Maustaste das Kontextmenü aufgerufen werden.