Silverlight Snippet: Bild-Reflexion a la CoverFlow

Mit dem folgenden Trick können wir in Silverlight die Reflexion eines Bildes auf einer Glasoberfläche simulieren, wie es auch iTunes im CoverFlow-Modus tut. Kopiert dazu ersteinmal ein beliebiges Bild in euer Projekt und passt die beiden Bild-Pfade im folgenden Code entsprechend an:

<Grid x:Name="LayoutRoot">
        <Grid.Background>
            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                <GradientStop Offset="0" Color="Black" />
                <GradientStop Offset="0.4" Color="Black" />
                <GradientStop Offset="0.5" Color="#181818" />
                <GradientStop Offset="0.6" Color="Black" />
                <GradientStop Offset="1" Color="Black" />
            </LinearGradientBrush>
        </Grid.Background>

        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <!-- Original-Bild -->
            <Image Source="image.jpg" Width="320" Height="240"
                   Stretch="UniformToFill" Margin="0.5" />

            <!-- Reflexion -->
            <Image Source="image.jpg" Width="320" Height="240"
                   Stretch="UniformToFill" Margin="0.5"
                   RenderTransformOrigin="0.5,0.5">
                <Image.RenderTransform>
                    <ScaleTransform ScaleY="-1" />
                </Image.RenderTransform>
                <Image.OpacityMask>
                    <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                        <GradientStop Offset="0" Color="#60FFFFFF" />
                        <GradientStop Offset="0.9" Color="#00FFFFFF" />
                    </LinearGradientBrush>
                </Image.OpacityMask>
            </Image>
        </StackPanel>
    </Grid>

Ganz oben haben wir dem Grid einen leichten Gradienten verpasst, damit die Reflexion mehr zur Geltung kommt.

Der eigentliche Trick ist, zwei Image-Objekte mit demselben Bild untereinander in einem StackPanel zu verwenden. Wichtig ist dabei nur, dass die beiden Images exakt gleich groß sind. Während das obere Image ganz normal dargestellt wird, flippen wir das untere Image vertikal und lassen es langsam ausfaden.

Das Flippen bzw. Spiegeln erledigen wir mit einem ScaleTransform. Diese Transformation kann nicht nur Objekte skalieren, sondern bei der Verwendung von negativen Werten für ScaleX oder ScaleY auch horizontal oder vertikal spiegeln. Dabei darf man nicht vergessen, für das Zielobjekt RenderTransformOrigin auf den relativen Mittelpunkt des Objektes (0.5,0.5) zu setzen, da es sonst nicht wie gewünscht um dessen Mittelpunkt gespiegelt werden würde.

Für das Ausfaden verwenden wir die OpacityMask-Eigenschaft des unteren Images. Diese erwartet eine beliebige Brush, deren Alpha-Farbwerte die Opazität des Objektes an verschiedenen Stellen bestimmen. Wir geben hier eine LinearGradientBrush an, die zwischen den Farben #60FFFFFF und #00FFFFFF, also von oben angefangen vom Alpha Wert #60 bis nach unten zu #00, interpoliert und damit die Opazität des Images langsam bis zur vollständigen Transparenz verändert. Die OpacityMask ignoriert dabei die Rot-, Grün- und Blauwerte der Farben und verwendet ausschließlich den ersten Alpha-Wert.

Wenn ihr das Programm nun startet, sollte es etwa so aussehen:

snippet_reflection

Silverlight Snippet: Vollbildmodus aktivieren

Um eine Silverlight-Webseite in den Vollbildmodus zu bringen, reicht eine Zeile C#-Code aus. Zu beachten ist aber, dass der Moduswechsel nur funktioniert, wenn die Ausführung des Codes vom Benutzer initiiert, also z.B. durch Klick auf einen Button aufgerufen wurde.

Im folgenden Beispiel steht der Code deswegen im Event-Handler eines Button Click-Events.
Wir erzeugen dazu zuerst einen Button in XAML und lassen uns einen Event-Handler ins Code-Behind generieren.

 <Grid x:Name="LayoutRoot">
        <Button Click="Button_Click"
                Content="In den Vollbildmodus wechseln!" />
 </Grid>

Im Event-Handler schreiben wir dann folgenden Code, um in den Vollbildmodus zu wechseln:

private void Button_Click(object sender, RoutedEventArgs e)
{
       Application.Current.Host.Content.IsFullScreen = true;
}

Wenn ihr nun auf den Button klickt, sollte die Silverlight-Webseite im Vollbildmodus angezeigt werden.

Silverlight Tutorial: Interaktion via Code-Behind

Willkommen zum dritten Silverlight Tutorial!

Diesmal werden wir lernen, wie man XAML- und C#-Code kombiniert, um etwas Interaktivität in unsere Webseite zu bringen.

Das Code-Behind

Im letzten Tutorial haben wir gelernt, wie man eine einfache Benutzeroberfläche in XAML erstellt. Leider war die noch sehr statisch und konnte nicht auf Benutzereingaben reagieren.

Während XAML sehr gut dafür geeignet ist, eine Oberfläche zu definieren, ist C#-Code das Mittel der Wahl, wenn es um die gesamte Applikations-Logik und das Reagieren auf Benutzereingaben geht.

Erstellt wie im letzten Tutorial beschrieben ein neues Silverlight Projekt.

Klickt jetzt im Solution-Explorer auf die Datei MainPage.xaml.cs. Ihr seht nun folgenden C#-Code:

public partial class MainPage : UserControl
{
        public MainPage()
        {
            InitializeComponent();
        }
}

Im Solution-Explorer ist erkennbar, dass die .cs Datei und die .xaml Datei durch einen Strich verbunden sind. Während in vielen Sprachen eine Klasse nur in genau einer Datei definiert werden kann, ist es in C# mit dem partial Schlüsselwort möglich, die Definition einer Klasse auf mehrere Dateien aufzuteilen.

In Silverlight wird dies verwendet, um eine Klassendefinition in XAML-Code (für die Benutzeroberfläche) und dem sogenannten Code-Behind (beispielsweise für das Behandeln von Benutzereingaben) aufzuteilen.

Wir werden diesmal zwei Möglichkeiten kennen lernen, wie XAML- und C#-Code miteinander kommunizieren können.

XAML-Objekte im Code-Behind ansprechen

Erzeugt wie folgt eine einfache Border in der MainPage.xaml:

<Grid x:Name="LayoutRoot">
        <Border x:Name="myBorder"
                Width="256" Height="256"
                Background="Black" />
</Grid>

Wenn ihr das Programm nun mit F5 ausführt, seht ihr unsere schwarze Border im Zentrum der Seite. Wir wollen nun als Beispiel die Hintergrundfarbe (also die Background-Eigenschaft) der Border aus dem Code-Behind ändern.

Geht dazu zurück zur MainPage.xaml.cs und erweitert den Konstruktor der Klasse um folgende Zeile:

public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            myBorder.Background = new SolidColorBrush(Colors.Orange);
        }
    }

Wenn ihr das Programm jetzt ausführt, ist die Border orange anstatt schwarz.

Im XAML-Code haben wir dem Border-Objekt mit x:Name einen Namen zugewiesen, über den wir das Objekt im Code-Behind der XAML-Datei ansprechen können. Zu beachten ist, dass x:Name keine Eigenschaft der Border-Klasse ist, sondern eher eine Meta-Information, die man nur in XAML festlegen kann. Zwar haben viele Klassen eine richtige Name-Eigenschaft, jedoch eben nicht alle, weswegen man der Konsistenz wegen immer x:Name verwenden sollte.

Wenn wir das Programm ausführen, wird zuerst der Konstruktor der Klasse MainPage aufgerufen. Dort steht standardmäßig nur der Aufruf der Methode InitializeComponent(), die nichts weiter macht, als unseren XAML-Code in C# Code umzuwandeln, der zur Laufzeit die in XAML definierten Objekte erzeugt (wir haben ja gelernt, dass XAML und C# größtenteils äquivalent und damit austauschbar ist).

Ihr könnt diesen generierten C#-Code sehen, indem ihr rechts auf die Methode klickt und dann “Gehe zu Definition” auswählt.

In der nächsten Zeile sprechen wir die in XAML definierte Border mit ihrem Namen an und weisen ihr eine andere Hintergrundfarbe zu.

Hier könnte man sich Fragen, warum wir ein SolidColorBrush-Objekt zuweisen, und nicht einfach soetwas wie Colors.Orange. Das hat den Grund, dass die Background Eigenschaft ein Objekt vom Typ Brush erwartet, Orange aber den Typ Color hat.

In Silverlight gibt es verschiedene von Brush abgeleitete Klassen, die von einfachen Farben (SolidColorBrush) über verschiedene Gradienten (z.B. LinearGradientBrush) bis hin zu Bildern (ImageBrush) oder sogar Videos (VideoBrush) reichen.

Das ermöglichst es, all das als “Hintergrundfarbe” von Elementen oder beispielsweise als Schriftfarbe von Texten zu verwenden, was ein viel flexibleres System ist, als nur einfache Farben (Color-Structs) zuweisen zu können.

Auf die Verwendung der verschiedenen Brushes werde ich in späteren Tutorials eingehen.

Im Code-Behind auf Events reagieren

Was uns jetzt noch fehlt, ist eine Möglichkeit, auf Benutzereingaben zu reagieren.

GUI-Elemente wie Buttons und auch unsere Border definieren in ihren Klassen Events, die unter bestimmten Bedingungen vom Objekt ausgelöst werden. So löst beispielsweise ein Button-Objekt das Click-Event aus, wenn der User auf den Button klickt.

Um im Code auf das Event zu reagieren, muss man einen Event-Handler bei dem Event registrieren. Das kann man sich ähnlich wie die Anmeldung für einen Newsletter vorstellen (was natürlich eine arg konstruierte Metapher ist ;-) ). Wenn der Anbieter einen neuen Newsletter herausgibt (ein Event auslöst), werden alle angemeldeten Benutzer (Event-Handler) und nur diese Benutzer informiert.

Bei uns wird ein Event-Handler eine einfache Methode im Code-Behind sein, die aufgerufen wird, sobald ein Objekt ein Event auslöst. Es gibt noch weitere Methoden wie anonyme Delegates, um auf Events zu reagieren, aber die sollen uns hier noch nicht beschäftigen.

Geht wieder zum XAML-Code und erweitert das Border-Tag wie folgt:

<Border x:Name="border"
                Width="256" Height="256"
                Background="Black"
                MouseLeftButtonDown="border_MouseLeftButtonDown"/>

Wenn ihr anfangt, im Border-Tag zu tippen, öffnet sich eine Liste mit allen Eigenschaften und Events des Objekts. Events sind mit einem Blitz gekennzeichnet. Sobald ihr das Event MouseLeftButtonDown per Doppelklick oder Druck auf die Return-Taste ausgewählt habt, sollte ein neues Kontext-Menü erscheinen, dass euch anbietet, einen neuen Event-Handler zu erstellen. Hier klickt ihr wieder doppelt auf “<Neuer Ereignishandler>”, worauf das Visual Studio automatisch eine Methode im Code-Behind generiert und ihren Namen im XAML einträgt.

Somit wurde für das Event MouseLeftButtonDown die Methode border_MouseLeftButtonDown als Event-Handler registriert und das Code-Behind sieht nun so aus:

 public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            border.Background = new SolidColorBrush(Colors.Orange);
        }

        private void border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

        }
    }

In diese Methode können wir nun Code schreiben, der ausgeführt werden soll, wenn jemand auf die Border klickt. Typischerweise haben solche Event-Handler Methoden zwei Parameter: Im ersten Parameter sender übergibt sich das Objekt, das das Event auslöst, selbst. Der zweite Parameter ist meist von einem für das Event spezifischen Typ, der weitere Informationen über das Event bereitstellt. Beim MouseDown-Event werden beispielsweise auch die Koordinaten übergeben, an denen der Klick stattfand.

Eine weitere Möglichkeit, einen Event-Handler zu registrieren, ist dies direkt im Code-Behind zu tun. Auch hier hilft uns das VisualStudio und generiert die entsprechende Methode automatisch. Schreibt folgendes in den Konstruktor der MainPage:

border.MouseLeftButtonUp += new MouseButtonEventHandler(border_MouseLeftButtonUp);

Nachdem ihr += getippt habt, könnt ihr zwei mal die Tab-Taste betätigen, um automatisch den Zuweisungscode und die Methode border_MouseLeftButtonUp generieren zu lassen.

Der komplette Code sieht nun so aus:

public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            border.Background = new SolidColorBrush(Colors.Orange);
            border.MouseLeftButtonUp += new MouseButtonEventHandler(border_MouseLeftButtonUp);

        }

        void border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

        }
    }

Wir haben jetzt jeweils eine Methode die aufgerufen wird, wenn der Benutzer auf die Border klickt (border_MouseLeftButtonDown), und die Maustaste wieder löslässt (border_MouseLeftButtonUp).

Wir wollen jetzt, um die Events zu visualisieren, die Hintergrundfarbe der Border je nach Event verändern, und erweitern den Code folgendermaßen:

public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            border.Background = new SolidColorBrush(Colors.Orange);
            border.MouseLeftButtonUp += new MouseButtonEventHandler(border_MouseLeftButtonUp);
        }

        void border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            border.Background = new SolidColorBrush(Colors.Green);
        }

        private void border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            border.Background = new SolidColorBrush(Colors.Red);
        }
    }

Wenn ihr das Programm jetzt ausführt, sollte die Border beim Gedrückthalten der linken Maustaste rot, und beim Loslassen grün werden.

Ihr könnt jetzt gerne mit anderen Events experimentieren, und auch mal andere Eigenschaften als die Hintergrundfarbe verändern, um ein Gefühl für das Event-System zu kriegen.

Im folgenden Beispielprojekt werden noch einmal verschiedene Events und deren Verarbeitung demonstriert. Das war’s dann soweit zu diesem Thema. Im nächsten Tutorial werden wir uns einen weiteren wichtigen Aspekt von Silverlight ansehen: DataBinding.

Beispielprojekt herunterladen

Silverlight Tutorial: Layout in XAML

Willkommen zum zweiten Silverlight Tutorial!

Diesmal werden wir die Grundlagen von XAML lernen, um ein einfaches Layout für eine Webseite zu erstellen. Los gehts!

Erstellen eines neuen Projekts

Startet das Visual Studio (bei euch wahrscheinlich die Visual Web Developer 2008 Express Edition) und klickt auf Datei -> Neues Projekt. Hier haben wir nun unter anderem die Wahl der Programmiersprache und des Projekttyps. Da wir eine Silverlight-Anwendung in C# schreiben wollen, wählt wie im folgenden Bild gezeigt die entsprechenden Einträge aus:

tut2.1

Der Projektname ist momentan unwichtig, wählt einfach etwas wie “SilverlightTutorial” und bestätigt mit OK.

Beim nächsten Dialog kann man optional ein Web-Projekt anlegen lassen, was wir aber nicht wollen. Entfernt also das Häkchen und bestätigt erneut mit OK. Nun wurde ein neues Silverlight-Projekt angelegt.

Die IDE ist recht selbsterklärend aufgebaut:

In der Mitte befindet sich der Code-Editor, in dem wir den C# und XAML Code schreiben werden.

Unten ist unter anderem ein Fehler-Fenster, das uns bereits vor dem Ausführen des Programms auf Fehler und Probleme hinweist.

Rechts ist der Solution-Explorer, der alle zum Projekt gehörigen Dateien anzeigt.

Und hier müssen wir bevor wir weitermachen eine kleine Änderung vornehmen: Standardmäßig wird die GUI mit einem grafischen Editor “zusammengeklickt”. Da dieser aber alles andere als gut funktioniert (es gibt dafür bessere Tools wie Expression Blend) und wir naheliegenderweise lernen wollen, wie man programmiert, deaktivieren wir den Editor und lassen uns wie folgt nur noch Code anzeigen:

Klickt rechts auf die Datei MainPage.xaml im Solution-Explorer und wählt Öffnen mit aus, worauf folgender Dialog erscheint:

tut2.2

Hier markiert ihr Quelltext-Editor, klickt auf Als Standard und bestätigt mit OK.

Das war’s auch schon. Weiter geht es mit einem der wichtigsten Themen in der Silverlight-Entwicklung: XAML.

Eine Anmerkung noch: Ab hier setzte ich das Verständnis von Grundbegriffen wie Objekt, Klasse und Vererbung vorraus. Solltet ihr darüber nichts wissen, kann ich euch nur nochmals das Galileo C# ObenBook ans Herz legen.

Enter XAML

In Silverlight wird in der Regel die gesamte grafische Oberfläche (GUI) in XAML-Dateien beschrieben. XAML steht für Extensible Application Markup Language und ist eine deklarative auf XML basierende Beschreibungssprache.

Öffnet jetzt die Datei MainPage.xaml, die etwa so aussehen sollte:

<UserControl x:Class="SilverlightApplication1.MainPage"
   	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  <Grid x:Name="LayoutRoot">

  </Grid>
</UserControl>

Im XAML-Code werden GUI-Elemente wie Buttons, Listboxen, Bilder usw. platziert und ihre Eigenschaften festgelegt.
Lasst euch jedoch nicht vom HTML-artigen Aussehen des Codes täuschen: Man kann XAML nahezu eins zu eins in C# abbilden, wo der obige Codeausschnitt etwa so aussehen würde:

MainPage mainPage = new MainPage();
Grid grid = new Grid();
mainPage.Content = grid;

Das heißt, auch in XAML definierte GUI-Elemente sind nichts weiter als CLR-Objekte, die zur Laufzeit erzeugt und deren Eigenschaften belegt werden. XAML macht es nur benutzerfreundlicher, jene Objekte zu definieren und daraus eine grafische Benutzeroberfläche zu designen.

Das erste, was wir auf diesem Gebiet lernen werden ist, wie man mit Hilfe von Panels das Grundlayout einer Anwendung festlegt.

Definieren eines Layouts in XAML

In Silverlight gibt es im wesentlichen drei Panel-Klassen, mit denen man auf verschiedene Weisen die Anordnung der GUI-Elemente steuern kann.

Zuerst schauen wir uns die StackPanel-Klasse an. Elemente in einem StackPanel werden einfach vertikal über- oder nebeneinander angeordnet (oder “gestapelt”, was im englischen to stack heißt). Dieses Panel sollte nur für kleinere Gruppen von Elementen und nicht für das grundlegende Seitenlayout eingesetzt werden, da es gerade für Anfänger oft ein unerwartetes Verhalten zeigt.

Schreibt nun folgendes in das Grid-Tag und startet die Anwendung, indem ihr die F5-Taste drückt.

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
      <Button Content="Ich bin ein Button!" Margin="8" />
      <TextBlock Text="Ich bin ein TextBlock!" Margin="8" />
      <TextBox Text="Ich bin eine TextBox!" Margin="8" />
</StackPanel>

Die Webseite sollte nun so aussehen:

tut2.4

Was genau haben wir also dort oben definiert?

Viele Elemente, die wir in XAML definieren, haben die Eigenschaften HorizontalAlignment und VerticalAlignment, die bestimmten, wie ein Element relativ zum übergeordneten Eltern-Element (bei uns ist das ein Grid) positioniert wird.

Da in unserem Beispiel beide Eigenschaften auf Center stehen, ist das StackPanel horizontal und vertikal im Grid zentriert. Nebenbei hat die StackPanel-Klasse auch eine Orientation-Eigenschaft. Sie legt fest, ob die Elemente im Panel vertikal (Orientation ist mit dem Wert Vertical belegt, das ist die Standardeinstellung) oder horizontal (mit dem Wert Horizontal) angeordnet werden.

Elemente die man in einem Panel definiert, werden implizit seiner Children-Eigenschaft hinzugefügt. Um das anschaulicher zu machen: Man könnte den obigen Code auch so schreiben:

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <StackPanel.Children>
          <Button Content="Ich bin ein Button!" Margin="8" />
          <TextBlock Text="Ich bin ein TextBlock!" Margin="8" />
          <TextBox Text="Ich bin eine TextBox!" Margin="8" />
    </StackPanel.Children>
</StackPanel>

Hier sehen wir eine weitere Art, Eigenschaften eines Elements festzulegen. Zum einen geht das direkt im Element-Tag (wie bei Horizontal- und VerticalAlignment), zum anderen auch direkt im Element mit ElementName.Eigenschaft. Beispielsweise würde der Codeausschnitt so aussehen, wenn wir die Alignments ebenfalls mit der zweiten Variante setzen:

<StackPanel>
      <StackPanel.HorizontalAlignment>
        Center
      </StackPanel.HorizontalAlignment>
      <StackPanel.VerticalAlignment>
        Center
      </StackPanel.VerticalAlignment>

      <StackPanel.Children>
        <Button Content="Ich bin ein Button!" Margin="8" />
        <TextBlock Text="Ich bin ein TextBlock!" Margin="8" />
        <TextBox Text="Ich bin eine TextBox!" Margin="8" />
      </StackPanel.Children>
 </StackPanel>

Es ist wichtig, sich die beiden Varianten zu merken, da wir später einige Eigenschaften nur noch mit der zweiten Variante setzen werden.

Was genau die drei Elemente im StackPanel sind, sollte selbsterklärend sein. In diesem Beispiel haben wir, anstatt Start- und End-Tags zu verwenden, die End-Tags mit “/>” abgekürzt, was oftmals die Übersichtlichkeit des XAML-Codes steigern kann.

Von jedem Element wurde die Margin-Eigenschaft belegt. Sie gibt an, wieviel Platz ein Element relativ zu seinen Nachbarelementen und zu seinem Eltern-Element haben möchte. Wird hier nur eine Zahl angegeben, hat das Element nach links, oben, rechts und unten denselben Abstand zu den umgebenden Elementen. Man kann hier auch durch Komma getrennt vier Zahlen angeben:

<Button Content="Ich bin ein Button!" Margin="2, 4, 6, 8" />

Sie geben in genau dieser Reihenfolge explizit die Abstände zu allen vier Seiten an: Links (2), oben (4), rechts (6), unten (8).

An dieser Stelle möchte ich kurz auf die Einheiten von Angaben wie Abstände oder Positionen in Silverlight eingehen.

Obwohl es scheint, dass ein Element mit einer Margin von 8, eben 8 Pixel Abstand erhält, ist dies nicht der Fall. Silverlight verwendet ein DPI- und Auflösungsunabhängiges Grafikmodell, das sicherstellt, dass Anwendungen mit verschiedenen Bildschirmkonfigurationen immer (relativ) gleich aussehen. Zwar sind Angaben in Pixel und in den Einheiten von Silverlight ähnlich, aber nicht identisch. Eine Linie der Länge 32 könnte also in Silverlight in Wirklichkeit 34 Pixel lang sein.

Da die Unterschiede sehr marginal sind, kann man dies meistens vernachlässigen. Wer aber beispielsweise Anwendungen schreibt, die pixelgenau arbeiten sollen, sollte das oben beschriebene im Hinterkopf behalten.

Und weiter geht’s mit der nächsten Panel-Klasse.

Die Grid-Klasse wird unter anderem für das Makro-Layout verwendet und ist vergleichbar mit HTML-Frames oder Tabellen. Man definiert im Grid Spalten und Zeilen, die feste oder relative Größen haben können, und weist den Elementen darin die Spalte und Zeile zu, in denen sie sich befinden sollen.

Ihr könnt jetzt das StackPanel aus dem Grid löschen, und stattdessen in das Grid-Tag (am besten ganz oben) folgendes schreiben:

<Grid.RowDefinitions>
      <RowDefinition Height="128" />
      <RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

Die Definition der Zeilen und Spalten erfolgt durch Belegung der RowDefinitions und ColumnDefinitions Eigenschaften des Grids.

Ihr habt für das Setzen der Höhe (Height-Eigenschaft einer RowDefinition) bzw. der Breite (Width-Eigenschaft einer ColumnDefinition) einer Spalte oder Zeile drei Möglichkeiten:

Es ist auch möglich, folgendes zu definieren:

<Grid.RowDefinitions>
      <RowDefinition Height="1*" />
      <RowDefinition Height="3*" />
</Grid.RowDefinitions>

Hier würde, auch wenn man zum Beispiel das Browserfenster vergrößert oder verkleinert, die zweite Zeile immer 3 mal so groß bleiben wie die erste. Die erste Zeile bekäme also ¼ des Platzes und die zweite ¾ .

Damit die Elemente in einem Grid wissen, in welcher Spalte und Zeile sie stehen sollen, gibt man diese Informationen wiefolgt im Element-Tag an:

<Button Grid.Row="0" Grid.Column="0" />

Dies würde bedeuten, dass der Button oben links in der ersten Spalte und in der ersten Zeile (für Informatiker ist ja bekanntermaßen das erste Element immer das 0te ;) ) platziert wird.

Zu beachten ist hier, dass Grid.Row und Grid.Column keine Eigenschaften der Button-Klasse sind, obwohl es den Anschein hat. Diese beiden Eigenschaften sind sog. Attached Properties, eine spezielle Art von Eigenschaft, auf die ich in späteren Tutorials eingehen werde. Momentan reicht es sich vorzustellen, dass sich ein Element solche Eigenschaften von anderen Klassen nur “ausleiht”.  Hier nun der komplette Code eines Beispiel-Grids mit zwei Elementen:

<Grid x:Name="LayoutRoot" ShowGridLines="True">
    <Grid.RowDefinitions>
      <RowDefinition Height="64" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Button Grid.Row="0" Grid.Column="0"
            Content="Ein Button"
            Margin="32" />

    <Border Grid.Row="1" Grid.Column="1"
            Background="Orange"
            BorderBrush="Black" BorderThickness="4"
            CornerRadius="8"
            Margin="32">
        <TextBlock Text="Hier kann genau ein Element rein!" />
    </Border>

</Grid>

Oben im Grid-Tag haben wir die Eigenschaft ShowGridLines belegt, die uns zum Testen die Spalten- und Zeilenbegrenzungen durch Linien anzeigt.

Wenn ihr das Programm nun ausführt, liegt oben links ein Button, während der untere linke Platz von einer Border eingenommen wird.

Die Border-Klasse repräsentiert einen Rahmen mit einer Hintergrundfarbe (Background), einer Rahmenfarbe (BorderBrush) und einer Rahmendicke (BorderThickness).

Die CornerRadius-Eigenschaft gibt an, wie stark die Rundungen an den Ecken sind. Wie bei der Margin-Eigenschaft kann man auch hier vier durch Komma getrennte Werte angeben, um für jede Ecke eine andere Rundung zu erreichen.

Eine Border hat im Gegensatz zur Children-Eigenschaft der Panels, die mehrere Elemente aufnehmen kann, eine Content-Eigenschaft, die nur ein Element in der Border erlaubt.

Schreibt man ein Element in das Border-Tag, wird (analog zu den Panels) implizit die Content-Eigenschaft mit diesem Element (in unserem Beispiel ein TextBlock) belegt.

Um mehr als ein Element in einer Border zu platzieren, kann man einfach ein Panel als Content festlegen, in dem man dann wieder beliebig viele Elemente setzen kann.

Die dritte Panel-Klasse ist das Canvas. Hier werden Elemente nicht wie in den anderen Panels relativ, sondern absolut durch Angabe von X- und Y-Koordinaten platziert. Dieses Panel sollte nicht für Layout-Zwecke verwendet werden. Es gibt jedoch Fälle, wo das absolute Positionieren von Elementen notwendig ist. Hier ein Beispiel:

<Grid x:Name="LayoutRoot">
    <Canvas>

      <Ellipse Canvas.Top="128" Canvas.Left="256"
               Width="64" Height="64"
               Fill="Orange"
               Stroke="Black" StrokeThickness="4" />

    </Canvas>
</Grid>

Ähnlich wie beim Grid, erfolgt die Angabe der Position eines Elements durch das Setzen der Attached Properties Canvas.Top und Canvas.Left. Der Koordinatenursprung (der Punkt 0,0) befindet sich in Silverlight nebenbei immer links oben.

Die Ellipse-Klasse ist ein Beispiel eines Shapes, wozu auch Klassen wie Rectangle und Line gehören. Shapes (genauer: von der Klasse Shape abgeleitete Klassen) repräsentieren einfache geometrische Formen und können keine weiteren Elemente als Inhalt zugewiesen bekommen.

Analog zur Border haben auch Shapes eine Hintergrundfarbe (Fill), eine Rahmenfarbe (Stroke) und eine Rahmendicke (StrokeThickness).

Hier endet unser Einstieg in XAML. Ihr müsstet nun in der Lage sein, Panel-Klassen zu verwenden, um einfache Layouts in XAML zu erstellen.

Im nächsten Tutorial werden wir uns ansehen, wie man XAML- und C#-Code verbindet und so eine interaktive Silverlight-Anwendung erstellt.

Beispielcode herunterladen

Hallo Welt!

Hallo Web 2.0 Welt!

Willkommen auf meinem neuen Blog. Nach langer langer Zeit der Inaktivität meiner alten Homepage, habe ich mich entschieden, eine neue im Blog-Format zu erstellen. Ganz ohne viel Schnick-Schnack und mit einem klaren und einfachen Design.

Diese Seite soll hauptsächlich eine Anlaufstelle für Silverlight-Interessierte sein und auch meine eigenen Silverlight-Projekte vorstellen. In Zukunft habe ich vor, eine umfangreiche Tutorial-Serie über die Programmierung in Silverlight zu schreiben, die auch für absolute Anfänger geeignet ist. Aber auch über andere Themen, rund ums Programmieren oder über etwas ganz anderes, werde ich hier regelmäßig schreiben.

Wegen der relativ wenigen Zeit, die ich momentan für das Schreiben habe, sehen einige Bereiche noch ziemlich leer aus. Im Moment ist die Seite quasi noch eine Beta-Version, ein Work-in-progress. Hoffentlich habt ihr trotzdem Spaß mit einigen meiner Projekte, die ich in der entsprechenden Sektion verlinkt habe. In den nächsten Tagen werde ich zwei bis drei neue Tutorials veröffentlichen. Ab da sollte dann hier relativ regelmäßig neuer Content in Form von Tutorials und Projekten zu finden sein.

Der Name eality wurde für diesen Blog nicht zufällig gewählt. Es ist der Projektname eines neuen Chatsystems, an dem ich weiterhin arbeite. Jedoch hat das Projekt inzwischen so viele Revisionen und Redesigns erfahren, dass ich lieber keine Versprechen machen möchte, wann es fertig ist ;-)

Bis dahin wünsche ich euch viel Spaß mit meinen Silverlight-Projekten. Schaut einfach mal ab und zu vorbei.

Andrej

« geh zurückweiter umsehen »