Silverlight Snippet: Setzen von Attached Properties im Code-Behind

Obwohl es für die meisten Silverlight-Entwickler trivial sein wird, dürften gerade Anfänger sich fragen, wie sie Eigenschaften wie Canvas.Top oder Grid.Row nicht nur im XAML, sondern auch im C# Code-Behind festlegen. Alle Klassen, die solche Attached Properties definieren, haben dazu statische Set- und Get-Methoden, mit dem dies möglich ist.

Zum Beispiel kann man das hier…

<Button x:Name="myButton" Grid.Row="0" />
<Button x:Name="myButton" Canvas.Top="0" />

…folgendermaßen in C# festlegen:

Grid.SetRow(myButton, 0);
Canvas.SetTop(myButton, 0);

Das Abfragen der Werte funktioniert ähnlich:

int row = Grid.GetRow(myButton);
double top = Canvas.GetTop(myButton);

Natürlich könnt ihr so nicht nur die Eigenschaften eines Elements setzen, das ihr in XAML mit einem Namen versehen habt, sondern auch mit einer Referenz auf ein Objekt, das ihr direkt im Code-Behind erstellt habt.

Kaffeepause

Vor kurzem fand ich einen Seite, die in interessanter Form die Geschichte des Lieblingsgetränks eines jeden Programmierers beschreibt: Kaffee. (Obwohl erstaunlich viele unserer Art inzwischen der dunklen Seite des koffeinfreien Genusses verfallen sind: Dem Tee.)

15 Things Worth Knowing About Coffee

Sehr schön gemachte Illustration, wie ich finde.

Und ein kurzes Statusupdate: Ich bin leider gerade ziemlich mit diversen Projekten ausgelastet, sodass ich nicht genau sagen kann, wann ich das nächste Tutorial schreiben kann. Eventuell lade ich als Lückenfüller ein neues kleines Silverlight-Projekt hoch.

Na dann bis zum nächsten Update.

Das eality.de Forum ist online!

Ab heute habt ihr die Möglichkeit, bei Fragen zur Silverlight- und WPF-Programmierung oder für generelles Feedback bezüglich der Webseite das eality.de Forum zu verwenden.

Ihr könnt dort auch als Gast, also ohne Registrierungszwang, Beiträge erstellen.

Ich wünsche allen Besuchern fröhliches posten!

Silverlight Snippet: Freihand zeichnen

In Silverlight ist es mit der InkPresenter-Klasse möglich, mit der Maus auf einer virtuellen Leinwand freihand zu zeichnen. Wir müssen dazu lediglich einige Maus-Events des InkPresenters abfangen und entsprechend verarbeiten. Dazu definieren wir ersteinmal einen InkPresenter im XAML:

<Grid x:Name="LayoutRoot">

        <InkPresenter x:Name="inkPresenter"
                      Background="Beige"
                      MouseLeftButtonDown="OnMouseDown"
                      MouseLeftButtonUp="OnMouseUp"
                      MouseMove="OnMouseMove" />

</Grid>

Im Code-Behind definieren wir folgende private Variablen:

private DrawingAttributes attributes;
private Stroke currentStroke;

Die DrawingAttributes-Klasse repräsentiert die Eigenschaften unseres virtuellen Pinsels wie Farbe oder Strichstärke.
Ein Stroke stellt die aktuell gezeichnete Figur (bzw. den gezeichneten Strich) dar, die aus einer Sammlung von Punkten besteht.

Im Konstruktor der MainPage legen wir die Eigenschaften unseres Pinsels fest:

public MainPage()
        {
            InitializeComponent();

            attributes = new DrawingAttributes();
            attributes.Color = Colors.Blue;
            attributes.Height = 10;
            attributes.Width = 2;
        }

Neben der Farbe legen wir auch die Größe des Pinsels fest. Dabei wählen wir in diesem Beispiel eine unterschiedliche Höhe und Breite, um einen kalligrafischen Effekt ähnlich eines Füllfederhalters zu erzielen.

Wenn der Benutzer die Maustaste drückt, erzeugen wir einen neuen (bisher aus keinen Punkten bestehenden) Strich, geben ihm die gewünschten Pinseleigenschaften mit und fügen ihn der Liste von Strichen des InkPresenters hinzu:

 private void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            currentStroke = new Stroke();
            currentStroke.DrawingAttributes = attributes;;
            inkPresenter.Strokes.Add(currentStroke);
        }

Lässt der Benutzer die Maustaste wieder los, setzen wir den aktuellen Strich auf null, um im nächsten Event zu merken, dass gerade nicht gezeichnet werden soll:

private void OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            currentStroke = null;
        }

Im MouseMove-Event schließlich fügen wir alle Punkte, die seit der letzten Mausbewegung gezeichnet wurden, unserem Strich hinzu. Dies tun wir aber nur, wenn die Maus noch immer gedrückt wird (currentStroke also nicht null ist). Die seit dem letzten Event hinzugekommenen Punkte erhalten wir aus einem der Argumente (MouseEventArgs) des Event-Handlers:

private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (currentStroke == null)
                return;

            foreach (StylusPoint point in e.StylusDevice.GetStylusPoints(inkPresenter))
                    currentStroke.StylusPoints.Add(point);
        }

Wenn ihr das Programm jetzt ausführt, solltet ihr wie gewünscht mit der Maus auf der Silverlight-Page zeichnen können.

Silverlight Snippet: Dateien speichern und laden

Seit Silverlight in der dritten Version erschienen ist, gibt es neben der Möglichkeit, vom Benutzer ausgewählte Dateien in die Silverlight-Anwendung zu laden auch eine Möglichkeit, Dateien lokal auf dem Rechner des Benutzers zu speichern. Die beiden dafür zuständige Klassen sind OpenFileDialog und SaveFileDialog, deren Verwendung ich hier kurz demonstrieren möchte.

Im XAML definieren wir folgendermaßen eine TextBox und einen Laden- sowie einen Speichern-Button, um geschriebene Textdateien in die TextBox zu laden oder als Datei abzuspeichern:

 <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <TextBox Grid.Row="0" Margin="16"
                 x:Name="textBox"
                 AcceptsReturn="True" />

        <StackPanel Grid.Row="1" Margin="16"
                    Orientation="Horizontal">
            <Button Content="Laden" Click="OnLoad" />
            <Button Content="Speichern" Click="OnSave"
                    Margin="16,0,0,0"/>
        </StackPanel>

    </Grid>

Im Code-Behind sehen die Event-Handler der Buttons wie folgt aus:

   private void OnLoad(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Textdatei (*.txt)|*.txt";
            bool? result = dialog.ShowDialog();

            if (result.HasValue && result.Value)
            {
                StreamReader reader = dialog.File.OpenText();
                textBox.Text = reader.ReadToEnd();
                reader.Close();
            }
        }

        private void OnSave(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "Textdatei (*.txt)|*.txt";
            bool? result = dialog.ShowDialog();

            if (result.HasValue && result.Value)
            {
                StreamWriter writer = new StreamWriter(dialog.OpenFile());
                writer.Write(textBox.Text);
                writer.Close();
            }
        }

Um das Beispiel minimal zu halten, habe ich nur die Filter-Eigenschaft der beiden Dialoge belegt, die angibt, welche Art von Dateien gelesen und gespeichert werden können. Es ist hier auch möglich, beim Filter mehrere Dateiendungen anzugeben: “Textdateien (*.txt)|*.txt|JPEG-Bilder (*.jpg)|*.jpg”. Dabei ist jeweils die erste Angabe vor dem vertikale Strich die Beschreibung des Dateiformates, die man im Klartext im Dialog sieht, und die zweite Angabe die letztendlich erwartete Dateiendung.

Zudem hat der OpenFileDialog eine Multiselect-Eigenschaft, mit der man mehr als eine Datei auswählbar macht. Nach dem Öffnen wäre dann anstatt der File-Eigenschaft Files belegt, was die Liste der geöffneten Dateien enthält, die man beispielsweise in einer Schleife durchlaufen könnte.

Der Aufruf von ShowDialog() liefert einen besonderen Datentyp zurück: Einen Nullable<bool>. Dieser Datentyp kann durch bool? abgekürzt werden. Nullable ist eine Wrapper-Struktur, die es auch Wertetypen wie bool oder int erlaubt, wie Referenztypen den Wert null anzunehmen. Dessen HasValue-Eigenschaft fragt ab, ob ein (nicht null) Wert gesetzt wurde und Value enthält den eigentlichen bool-Wert. War der Rückgabewert von ShowDialog() ein bool mit dem Wert true, hat der User Dateien ausgewählt und wir können uns bei beiden Dialogen einen Stream auf die Datei(en) zurückgeben lassen. Wir bekommen je nach Wahl des Dialoges einen nur les- oder schreibbaren Stream.

Aus Sicherheitsgründen hat man in Silverlight nur auf den Namen der geöffneten Datei zugriff, nicht hingegen auf weitere Informationen wie den vollen Dateipfad auf dem lokalen Rechner.

Für die Verwendung von StreamReader und -Writer muss mit using der Namespace System.IO eingebunden werden. Ich werde hier nicht weiter auf die Verwendung von Streams eingehen. Interessierte können hier über ihre Verwendung nachlesen.

« geh zurückweiter umsehen »