Daily-Hour 38: TemplateBinding

6. März 2010 juergen79 Keine Kommentare

Aber ein ControlTemplate muss nicht immer statisch sein, denn man möchte ein Template wieder verwenden können und auch verändern. Über TemplateBinding ist eine Dynamisierung des Templates möglich. Mit der Erweiterung von XAML und der Reaktion des XAML-Parser wird die Angabe nicht als statischen XAML-Text behandelt.

Dabei werden Parameter bei der Deklaration eines Controls angegeben werden, welche innerhalb des Templates verwendet werden, in dem über TemplateBinding auf deren Name verwiesen werden.

<Canvas.Resources>
    <Style x:Key=”TemplateStyle” TargetType=”Button”>
         <Setter Property=”Template”>
             <Setter.Value>
                  <ControlTemplate TargetType=”Button”>
                       <Grid>
                           <Ellipse Width=”{TemplateBinding Width}” Height=”{TemplateBinding Height}”>
                               <Ellipse.Fill>
                               <RadialGradientBrush GradientOrigin=”.3,.6″ Center=”.5,.5″>
                                   <GradientStop Color=”DarkBlue” Offset=”0″/>
                                   <GradientStop Color=”Blue” Offset=”2″/>
                               </RadialGradientBrush>
                               </Ellipse.Fill>
                           </Ellipse>
                           <TextBlock Text=”Button” FontFamily=”Verdana” FontSize=”14″
                                  Foreground=”{TemplateBinding Foreground}”
                                  VerticalAlignment=”Center” HorizontalAlignment=”Center”/>
                       </Grid>
                  </ControlTemplate>
             </Setter.Value>
         </Setter>
    </Style>
</Canvas.Resources>

Über TemplateBinding werden nun die beim Button definierten Parameter Width und Height der Ellipse zugewiesen und die Textfarbe wird mit der Eigenschaft Foreground dem TextBlock zugewiesen. Es können jedoch nur Parameter benützt werden, die für den jeweiligen TargetType gültig sind.

Daily-Hour 37: Customized Controls

5. März 2010 juergen79 Keine Kommentare

Wie man Control-Elemente und Styles definiert und anpasst wurde bisher schon besprochen. Mit Styles können diverse Eigenschaften für andere Control-Elemente übernommen werden. Aber man kann auch weitere Anpassungen im ControlTemplate vornehmen. Hier kann man jedes Control grafisch anpassen, das geht über die üblichen definierbaren Eigenschaften hinaus.

Mit dem ControlTemplate kann man das Control komplett neu- bzw. umgestalten. Man kann die Form ändern oder weitere Controls hinzufügen. Außerdem könnte auch Benutzerinteraktionen festlegen, wie zB MouseEnter-Event. Die spezifischen Methoden des Controls bleiben weiterhin erhalten.

Deklaration von ControlTemplate
Es gibt mehrere Möglichkeiten wie man ControlTemplates defnieren könnte, die sinnvollste ist als Ressource, weil man diese mehrmals wiederverwenden kann:

<Canvas …>
    <Canvas.Resource>
         <ControlTemplate x:Key=”ButtonTemplate” TargetType=”Button”>
              …
         </ControlTemplate>
    </Canvas.Resource>
    <Button Content=”OK” Template=”{StaticResource ButtonTemplate}”/>
</Canvas>

Aufbau von ControlTemplates
Ein ControlTemplate ist nichts anderes als ein in XAML definierter Code in dem mehrere Elemente zusammengesetzt werden. Es muss immer ein RootElement (vom Typ FrameworkElement) haben, das weitere Elemente enthalten kann. Für das gewünschte Control ein eigener “visueller Baum” aufgebaut. Hier werden die Einzelheiten des Controls sowie dessen Parameter wie in XAML üblich festgelegt.

<Canvas Background=”White”>
<Canvas.Resources>
     <Style x:Key=”StyleTemplate” TargetType=”Button”>
          <Setter Property=”Template”>
              <Setter.Value>
                   <ControlTemplate TargetType=”Button”>
                       <Grid>
                           <Ellipse Width=”150″ Height=”100″>
                               <Ellipse.Fill>
                                   <RadialGradientBrush GradientOrigin=”.4,.6″ Center=”.2,.4″>
                                       <GradientStop Color=”DarkBlue” Offset=”0″/>
                                       <GradientStop Color=”Blue” Offset=”2″/>
                                   </RadialGradientBrush>                               
                               </Ellipse.Fill>
                           </Ellipse>
                           <TextBlock Text=”Button” FontFamily=”Verdana” FontSize=”14″ Foreground=”White”
                                 VerticalAlignment=”Center” Horizontal=”Center”/>
                       </Grid>
                   </ControlTemplate>
              </Setter.Value>
          </Setter Property=”Template”>
     </Style>
</Canvas.Resources>
<Button x:Name=”TestButton” Style=”{StaticResource StyleTemplate}” Margin=”10″ Click=”Click_TestButton”/>

</Canvas>

Jetzt wurde ein dem Button ein Style zugewiesen, der ein ControlTemplate definiert. Für den Button wird eine Ellipse mit Farbverlauf sowie einen TextBlock zur Anzeige von Text. Der Button-Deklaration wird ebenso ein Click-Ereignis zugewiesen. Es ist identisch mit der Vorangehensweise bei normalen Buttons.

Daily-Hour 36: Styles

4. März 2010 juergen79 Keine Kommentare

Ein wichtiger Punkt in Silverlight sind sicher das Styling von Applikationen, aber man will nicht jedesmal alles neu definieren sondern auch wiederverwenden.

Der Aufbau von XAML-Dokumenten ist sehr unfangreich und die Zuweisung von Attributen an einzelne Elementen sehr langwierig. Deshalb wünscht man sich Vereinfachungen, für Elemente die gleich aussehen soll. In Silverlight funktioniert das mit Styles, welche als Ressource zugewiesen. Wo der Style definiert werden soll, bleibt dem Entwickler überlassen und ist vom Anwendungsfall abhängig. Man könnte Styles an jeder beliebigen Stelle in der XAML-Struktur definiert werden, je höher dies geschieht, desto sinnvoller ist es. Die Zuweisung wird meistens in der Regel bei Bereichselementen oder im UserControl durchgeführt.

Es  besteht auch die Möglichkeit, die Ressource als Application.Resoure in der App.xaml zu definieren, dann kann man die Style-Definiation in der gesamten Applikation verweden. Für alle Definitionen gilt, es muss innerhalb einer Ressource gemacht werden. Die Definition eines Styles bedarf generell 2 Schritte:

  1. Definieren des Styles
  2. Zuweisung des Styles

Style-Definition
Ein Style wird immer nach folgt aufgebaut:

<Object.Resource>
    <Style …>
        <!– Setter für den Style>
   
</Style>
    <!– Weitere Styles–>
</Object.Resource>

Man kann inner halb der Ressource beliebig viele Style-Blöcke definieren. Ein jeder Style-Block besteht aus dem Style-Tag sowie die zwei Attributen:
    <Style TargetTyp=”TextBlock” x:Key=”TextBlockBlue_12px”>

        <!– Setter für den Style–>

    </Style>

Über TargetTyp wird festgelegt, für welchen Control-Typ der Style definiert ist. Der Style kann nur Controls diesen Typs zugewiesen werden. Mit x:Key wird ein eindeutiger Name des Style zugewiesen, damit der Style später auch einem Control zugewiesen werden kann.

Innerhalb des Style-Tags können verschiedenste Setter definiert werden. Die Setter sind die Definition für den Stil und wird wie folgt aufgebaut:
   

        <Setter Property=”Attribut”>
              <Stetter.Value>
                  <!– Wert –>
              </Stetter.Value>
        </Setter>

Property verweist immer auf die Eigenschaft eines Elementes, diese muss jedoch immer auf die entsprechende Eigenschaft des im TargetTyp definierten Elements sein. In Silverlight ist nur die explizite Zuweisung eines bestimmten Control-Typs durchgeführt werden.

Beispiel:

<UserControl x:Class=”SilverlightApp1.Page” …>
    <UserControl.Resources>
        <Style TargetTyp=”TextBlock” x:Key=”TxtBlockStyle”>
            <Setter Property=”Foreground” Value=”Blue”/>
        </Style>
    </UserControl.Resources>
</UserControl>

Um weitere Eigenschaften eines Styles zu definieren, setzt man weitere Setter innerhalb des Style-Tag. Sollte ein Value aus mehreren Werten bestehen, so werden diese per Element-Schreibweise definiert:

       <Setter Property=”Background”>
            <Setter.Value>
                   <LinearGradientBrush StartPoint=”0.0″ EndPoint=”0.1″>
                         <GradientStop Color=”Blue” Offset=”0″/>
                         <GradientStop Color=”White” Offset=“1.4″/>
                   </LinearGradientBrush>
           <Setter.Value>
       </Setter>

Der Background wird definiert, so wie er es auch ohne Style definiert worden wäre.

Style-Zuweisung

Der definierte Style sollte auch verwendet werden und deshalb muss das Control dem in TargetType angegebenen Typ entsprechen, dann kann der Style durch { und } dem Control-Element zugewiesen werden. Der Parameter StaticResource wird zwingend benötitgt, um den Parser mitzuteilen, dass der XAML-Wert aus einer definierten Ressource ausgewertet werden soll.

<TextBlock Style=”{StaticResource TxtBlockStyle} Text=”irgendein Text”/>

Man kann aber auch durch Style definierte Eigenschaften überschreiben, in dem man einfach die jeweilige Eigenschaft beim Element direkt neu definiert. Die direkt zugewiesenen Parameter haben immer die höhere Priorität.

Der Einsatz von Styles kann jede Menge Zeit ersparen, besonders wenn er über App.xaml für die gesamte Applikation zur Verfügung stehen soll.

Daily-Hour 35: Steuerelement Teil 10: ProgressBar

25. Februar 2010 juergen79 Keine Kommentare

Im Internet tauchen häufig Fortschrittsanzeigen auf, bei Downloads oder sonstigen Anwendungen, wie Installationsroutinen. Der ProgressBar dient, wie wir schon in einen vorigen Eintrag erwähnt, zeigt er Fortschritte an (englisch  Progress). Standardmäßig wird es mit einem Balken, der mit einer Frage gefüllt wird. Der User weiß, das ein ungefüllter Balken 0 % und ein gefüllter Balken 100% darstellt. Wobei letzters den Abschluss der Aktion.

Der ProgressBar ist ein Control, das in Silverlight zur Verfügung gestellt wird, um den Entwickler eine einfache Möglichkeit zu bieten, dies effizient abzubilden. Die Größe des des ProgressBar wird wie so oft über Width und Height definiert.

Es gibt zwei unterschiedliche Darstellung für einen ProgressBar:

  • man kann den ProgressBar dazu nutzen, einen fortlaufenden oder anhaltenden Zustand anzuzeigen, der nicht terminiert, und ein Ende nicht abzulesen ist, der ProgressBar zeigt, deshalb nur einen Musterverlauf an. Dieses Verhalten kann mit dem Parameter IsIndeterminate=”True” herbei geführt werden.
  • Wenn ein Fortschritt sichtbar sein kann bzw. es zu einem Ende kommt, wie zB beim Laden eines Bildes, braucht man keinen Parameter dafür extra angeben, weil IsIndeterminate defaultmäßig auf false gesetzt ist.

Über den Parameter Value erhält man den aktuellen Fortschritt bzw. könnte auch einen Wert setzen, der Wertebereich reicht von 0 bis 100. Ein Vorgang muss aber nicht immer bei 0 Anfangen bzw. bei 100 aufhören, man kann den Start und Endwert auch über Minimum bzw. Maximum ändern. Eine Möglichkeit ist es, die Anzeige für Zeitmäßiges laden zu verwenden, dafür müsste man den Bereich nur auf 60 Einheiten beschränken.

Der Event-Handler für den ProgressBar ist das ValueChanged-Event, das immer dann Eintritt wenn sich der Value-Wert ändert. Man könnte meinen, dass dies nicht besonders sinnvoll ist, da die Werte ja händisch geändert werden. Aber man kann eine Klasse vom ProgressBar ableiten, über das sich das ValueChange-Ereignis selbst abprüft. Beim erstmaligen Auftreten wird der Balken sichtbar gemacht und wenn man 100 erreicht wird, dann wird die Sichtbarkeit deaktiviert.

Alternativ könnte man den Download-Fortschritt auch als Zahl anzeigen.

Daily Hour 34: Steuerelement Teil 9: Mediaelement

24. Februar 2010 juergen79 Keine Kommentare

Um multimediale Inhalte online zu stellen gibt es in Silverlight das MediaElement-Control. Audio- und Videoformate unterliegen häufigen Formatänderungen und -verbesserungen. Welche Formate werden von Silverlight unterstützt?

  • Video:
    • RAW-Video
    • YV12 – YCrCb(4:2:0)
    • RGBA – 32-Bit-Alpha Rot, Grün, Blau
    • WMV1: Windows Media Video 7
    • WMV2: Windows Media Video 8
    • WMV3: Windows Media Video 9
    • WMVA: Windows Media Video Advanced Profile, non-VC-1
    • WVC1: Windows Media Video Advanced Profile, VC-1
    • H264 (ITU-T H.264/ISO MPEG-4 AVC)
  • Audio
    • WAV: lineare 8- und 16-Bit Pulscodemodulation
    • WMA Standard: Windows Media Audio v7, v8, v9.x Standard
    • WMA Professional: Windows Media Audio v9.x – v10 Professional
    • AAC: ISO Advanced Audio Coding

Weiters werden folgende Webprotokolle/-shemas unterstützt:

  • http
  • https
  • ms-wmsp (es können auch die Moniker mms und rtsp verwenden, werden aber in http-streaming geändert)
  • UNC (\\computername\freigabeverzeichnis) – zu beachten gilt, das dies als Stream abgerufen werden muss.

So jetzt sind die wichtigsten Formate und Protokolle besprochen, wird es Zeit ein MediaElement zu definieren:

<MediaElement source=”video.wmv” x:Name=”Vid”/>

Wie beim Image sind auch beim MediaElement die meisten Eigenschaften verwendbar, wie

  • Stretch
  • Width/Height
  • Brushes

Wie bei Image können die Mediendatein innerhalb der XAP-Datei gespeichert werden oder auf einer externen Quelle befinden.

Im allgemeinen gibt es 3 Arten wie eine Mediendatei abgespielt werden kann:

  • Download: die Datei wird erst auf die lokale Festplatte geladen und sobald diese komplett ist, wird diese abgespielt.
  • Progressiver Download: hierbei wird nicht gewartet bis das File vollständig heruntergeladen ist, sondern immer teile (gepuffert) und dann mit dem Abspielen begonnen. Die Datei wird im normalfall ohne Verzögerung abgespielt, aber ist von der Bandbreite der Internetverbindung abhängig
  • Streaming: hier wird die Datei nie komplett heruntergeladen, sondern immer nur häppchenweise. Im Unterschied zum progressiven Download, der Puffer überschreibt sich ständig selbst und die Datei wird niemals komplett heruntergeladen.

Defaultmäßig ist AutoPlay auf true gesetzt, d. h. die Datei wird gleich abgespielt. Sollte jedoch mit dem abspielen der Datei gewartet werden, so ist der Wert auf false zu setzen. Eine weitere Erweiterung gegenüber ist Volume, der als Double-Wert definiert ist, hier kann die Lautstärke von 1 (volle Lautstärke) bis 0 (Mute), abhängig von der Systemlautstärke eingestellt werden. Um den Ton stumm zu schalten gibt es mit IsMute eine weitere Möglichkeit dies zu tun, der Vorteil, soll der Ton wieder aktiviert werden, so wird bei der letzten eingestellten Lautstärke der Ton wieder ausgegeben. Eine weitere Audio-Eigenschaft ist Balance (ebenfalls ein Double) mit dem die Balance zwischen rechten und linken Lautsprecher eingestellt werden kann, der Wertebereich liegt von -1 bis 1. -1 ist der linke Lautsprecher, 0 ausgeglichen und 1 der rechte.

Das MediaElement kann sich abhängig von der aktuellen Aktion verschiedene Zustände annehmen. Zustandsänderung des MediaElements führ zu einem CurrentStateChanged. Hierbei sind folgende States möglich:

  • Opening: Media-Datei wird validiert und für den Empfang vorbereitet, anschließend wir das Opened-Ereignis ausgelöst
  • Buffering: die ersten Sequenzen der Media-Datei werden heruntergeladen und in den Puffer geschrieben.
  • Playing: die Datei wird abgespielt
  • Paused
  • Stopped
  • Closed: zeigt keinen Inhalt an und es ist keine Mediadatei mehr vorhanden/geöffnet

Wichtige Ereignise im Zusammenhang mit MediaElementen sind:

  • BufferingProgressChanged
  • DownloadProgressChanged
  • MediaOpened
  • MediaFailed
  • MediaEnded
  • MarkerReached

Wie man diese Elemente einsetzen kann, wird in einem der folgenden Einträge zum Thema “Mediaplayer” behandelt.

Daily Hour 33: Steuerelement Teil 8: HyperlinkButton & Image

23. Februar 2010 juergen79 Keine Kommentare

HyperlinkButton

Mit dem HyperlinkButton kann man Hyperlinks im Silverlight-PlugIn verwenden und ist ein Content-Control, d.h. er kann Text, Bilder Figuren oder Bereichselemente enthalten. Die am meisten verwendete Variante ist der Content-Parameter und stellt einen Text als Hyperlink dar. Der Vorteil ist, das der Link schon standardmäßig vordefiniert ist.

In XAML ist der Standard-HyperlinkButton einfach zu definieren:

<HyperlinkButton Content=”Microsoft Silverlight Website”  NavigateUri=”http://www.silverlight.net” TargetName=”_blank” Margin=”5″/>

Mit dem Content-Parameter definiert man den Text mittels der Eigenschaft Underline könnte man den Link wie aus HTML-Dokumenten gewohnt aussehen lassen. NavigateUrl weißt man die URL, die aufgerufen werden soll, zu. Dann wäre noch TargetName zu erwähnen, diese Eigenschaft dient um fest zu legen, wie die URL aufgerufen werden soll. Wie aus HTML-Dokumenten gewohnt:

  • _blank: Die URL wird in einem neuen Fenster/Tab geöffnet.
  • _self: Die URL wird im gleichen Frame oder Browserfenster geöffnet. Dies ist auch die Standardmäßige Definition, falls nichts anderes angeführt wird.

Wie bei Content-Elementen bekannt, verfügt auch der HyperlinkButton über die Eigenschaften: Background, Border, BorderThickness, ClickMode und Font um den Button auch anpassen zu können. Mittels den Eventen MouseEnter und MouseLeave können zusätzliche Effekte umgesetzt werden, wie z das Färben des Links, wenn der Mauszeiger in den Bereich eindringt.

Image

Wann man sich das nächste Steuerelement Image anschaut, ist das Einbinden eines Bilds in eine Silverlight-Applikation relativ einfach und mit wenig XAML bereits erledigt:

<Image Source=”Penguins.jpg” />

Dabei kann man das anzuzeigende Bild über eine URI angegeben werden oder es ist Inhalt der XAP-Datei bzw. wird als Ressource in die DLL kompliert. Die häufigste Form ist das es Teil der XAP Datei ist oder liegt am selben Server, der auch die XAP-Datei bereitstellt.

Mit Source wird der Pfad und Dateiname des Bildes angegeben.

In Silverlight werden Bildformat JPEG und PNG untersützt, aber es werden nicht alle PNG-Spezifikationen enthalten. Silverlight unterstützt folgende Farbtiefen:

  • indizierte Farbe (1-Bit, 4-Bit oder 8-Bit-Farbtiefe pro Kanal).

  • Truecolor (24-Bit-Farbtiefe oder 32-Bit-Farbtiefe (pro Kanal) für Truecolor.
    Alpha wird in 32-Bit-, aber nicht in 24-Bit-PNG-Dateiformaten unterstützt.

Graustufen-PNGs werden noch nicht unterstützt.

Es kann auch vorkommen, das ein Bild nicht aufgefunden werden kann oder es sich um ein nicht unterstütztes Format handelt bzw. könnte auch die Datei defekt sein, deshalb gibt es das ImageFailed-Event, das ausgelöst wird, wenn es zu Problemen mit dem Aufruf der Datei kommt.

Es kann zwischen der Anfrage und Emfang zu Verzögerungen kommen, die normalerweise kaum bemerkbar sind, aber bei größeren Bildern sichtbar wir und zu mehrsekündigen Verzögerungen kommen könnte. Man spricht hier vom asynchronen Prozess. Silverlight kümmert sich zwar darum, das auf dem Empfang gewartet ist, dekodiert anschließend auch das Bild und zeigt es danach an. In XAML hat man keine Möglichkeit auf den Fortschritt des Downloads zu reagieren. Eine erfolgreiche Darstellung kann man nur feststellen, da kein ImageFailed-Event ausgelöst wird.
 
Aber durch den Code könnte man sich abhilfe schaffen. Man kann einerseits wie erwähnt mittels dem ImageFailed Parameter einen Event-Handler implementieren, der Alternativen zu Darstellung eines Bildes bietet oder auch einen Progressbar, damit der Anwender die Fortschritte beim laden des Bildes ersichtlich
        private void pic_Loaded(object sender, RoutedEventArgs e)
        {
            BitmapImage img = new BitmapImage(new Uri(“Pinguins.jpg”));
            img.DownloadProgress += new EventHandler<DownloadProgressEventArgs>(img_DownloadProgress);
            pic.Source = img;
        }

Zuerst erzeugt man ein Bitmap-Objekt, der Bitmap-Instanz wird schließlich ein Event-Handler zugewiesen, der den Fortschritt des Downloads anzeigt. Abschließend wird dem Image Bild dieses BitmapImage direkt zugewiesen

        private void img_DownloadProgress(object sender, DownloadProgressEventArgs e)
        {
            progress.Value = e.Progress;
            if (e.Progress == 100) progress.Visibility = Visibility.Collapsed;

        }

Der ProgressBar progress wird hier noch ein Wert zugewiesen, der den Fortschritt des Downloads anzeigt. Sollte das Bild schließlich vollständig geladen sein, wird der ProgressBar ausgeblendet.

Am Ende sollte noch kurz die Darstellungsmöglichkeiten des Bildes besprochen werden. Sollten zur Höhe und Breite des Bildes keine Angaben gemacht, wird das Bild in der Originalgröße dargestellt. Oft weiß man nicht, wie Groß der Ausgabebildschirm sein wird und da sind fixe Größenbeschränkungen sind da nicht optimal, besser ist es dafür Width und Height des Image-Controls festzulegen und dafür zu sorgen, das eine Darstellung des Bildes schön angezeigt wird, dafür gibt es den Parameter Stretch.

  • Non: es findet keine Anpassung des Bildes statt es wird so dargestellt, das die Originalgröße des Bildes erhalten bleiben. Dabei kann das Bild größer oder kleiner sein, als der definierte “Rahmen”.
  • Fill: Das Bild wird exakt an die Größe der BoundingBox angepasst. Die BoundingBox entspricht in dem Fall der definierten Höhe und Breite. Beim Bild kann es dadurch zu Verzerrungen kommen kann.
  • Uniform: Das Bild wird bestmöglich an die BoundingBox angepasst (entweder Breite oder Höhe des Bildes). Hierbei wird auf einer der es zu “Rändern” kommen, da nur eine Seite des angepasst wird und die andere Verhältnismäßig angepasst.
  • UniformToFill: Hier wird das Bild so angepasst, dass die BoundingBox komplett ausgefüllt werden kann, ohne das die Seitenverhältniss des Bildes zu zerstören. Die kleinere Seite wird angepasst, die größere wird beschnitten.

  • Uniform

Daily-Hour 32: Steuerelement Teil 7: DataGrid

22. Februar 2010 juergen79 Keine Kommentare

Nun haben wir schon die Daten aus einer ComboBox, die könnte man wieder weiterverwenden, da es aber alles String sind, fügen für den Daten einfach einen Boolean hinzu. Wenn es Daten aus einer Bücherei wären, würde der User sicher gerne wissen, ob es das Buch verfügbar ist.

Oder man definiert die Bücher über eine eigene Klasse, da im letzten Eintrag den einfacheren Weg gewählt wurde nehmen wir zum hinzufügen der Bücher eine eigene Klasse.

Damit das funktioniert müssen man die Klasse Book erweitern und fügt deshalb eine Methode zur Klasse hinzu:

       public Book(String titel, String autor, String verlag, Boolean verfuegbar)
        {
         
            this.Titel = titel;
            this.Autor = autor;
            this.Verlag = verlag;
            this.Verfuegbar = verfuegbar;
        }

Wenn das gemacht wurde kann die Klasse Books definiert werden, die Klasse Books muss wie im letzten Post erwähnt wurde, von ObservalbleCollection abgeleitet werden , damit es bei Änderung der Collection auch zu Änderung innerhalb der Klasse kommt.

Die Klasse Books enthält nur eine Methode:

    public class Books : ObservableCollection<Book>
    {
        public Books()
        {
            Add(new Book(“Silverlight 3: Crashkurs”, “Otto Fischer”, “Microsoft Press”, true));
            Add(new Book(“Pro Silverlight 3 in C#”, “Matthew MacDonald”, “Apress”, true));
            Add(new Book( “Silverlight 3″,”Uwe Rozanski”,”Mitp Verlag”,false));
            Add(new Book(“Introducing Microsoft Silverlight 3″,”Laurence Moroney”,”Microsoft Press”,false));
            Add(new Book(“Das Affenpuzzle”, “David Harel”, “Springer Verlag”, true));
        }

    }

Als nächstes benötigen wir noch ein neues Assembly im UserControl, welches auch das DataGrid enthält:

xmlns:data=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”

Dann hätte man eigentlich schon fast alles vorbereitet, was man für eine einfache Darstellung der Daten benötigen. Jetzt braucht man nur noch ein DataGrid im XAML einfügen:

                <data:DataGrid x:Name=”Grid” Margin=”10″ Loaded=”Grid_Loaded”>
                        <data:DataGrid.Columns>
                        </data:DataGrid.Columns>
                    </data:DataGrid>

Im Loaded-Event müssen jetzt in der Methode nur noch Daten hinzugewiesen werden, am einfachsten geht es mit einer Zeile:

Grid.ItemsSource = new Books();

Das Grid schaut schon recht akzeptabel aus, ohne das man viel gemacht hat und die Boolean-Werte werden als CheckBox angezeigt. Die Zeilenfarbe wechselt jede Zeile, dadurch wird die Lesbarkeit erhöht. Die Farben für die Zeilen kann man wie üblich definieren, dazu dienen die Eigenschaften RowBackground und AlternateRowBackground definieren. Neben der üblichen Farbzuweisung (RowBackground=”Blue”) ist auch eine Zuweisung mittels Brush-Objekt, wie zB LinearGradientBrush.

Die Tabellenüberschrift wurde automatisch auf die Member-Namen gesetzt, über die die Klasse Book definiert wurde. Über die Spaltenüberschrift kann während der Laufzeit die Inhalte sortiert werden. Wenn dies nicht möglich sein sollte, kann man das über die Eigenschaft CanUserSortColumns ausgeschaltet werden, wenn der Wert auf false gesetzt wird.

Als nächstes kann man auch noch das Verändern der Spaltenbreite verbieten, dies geschieht mit CanUserResizeColums=”False”.  Was der User noch ändern könnte, wäre das Anordnen der Spalten, aber auch das könnte noch verboten werden: CanUserReorderColumns=”False”.

Der Vorteil durchs verwenden von DataGrid liegt auf der Hand, es werden:

  • die Anzahl der Spalten,
  • der Spaltentyp, 
  • die Breite der Spalte
  • der Name im Tabellenkopf (durch Namen der Member-Variablen)

automatisch ermittelt und

  • alternierende Farben für gerade/ungerade Zeilen zugewiesen und
  • Drag&Drop und Spalten reordering sowie Spalten Größenänderungen ermöglicht.

Dies geschieht alles ohne zusätzlichen Code, aber im Hintergrund gibt es natürlich die entsprechenden Events, die alles abarbeiten, wie zB wenn die Spalten neu angeordnet werden.

Man könnte auch die Spaltenüberschriften ausblenden (HeaderVisibility=”False”) oder auch die Tabllenlinien ausblenden (GridLines):

  • None – keine werden angezeigt
  • Horizontal – nur horizontale werden angezeigt.
  • Vertikal – nur die vertikalen werden angezeigt
  • All – default-Wert, es werden alle angezeigt

Jetzt gibt es nur noch eine Kleinigkeit, die eventuell stören könnte, da es im Code keine Umlaute gibt, sollte eventuell, die Spaltenüberschrift für Verfügbar geändert, das kann man über AutoGeneratingColumn=”Grid_AutoGeneratingColumn” machen und im Event-Handler dazu braucht es nur eine if-Abfrage, in der dem Header einen neuer String zugewiesen wird:

        private void Grid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            if (e.Column.Header.ToString() == “Verfuegbar”)
                e.Column.Header = “Verfügbar”;
        }

Daily-Hour 31: Silverlight Steuerelement Teil 6: ComboBox

20. Februar 2010 juergen79 Keine Kommentare

Die ComboBox ist eine Mischung aus ListBox und Textfeld, wobei das Textfeld einigen Einschränkungen unterworfen ist. Das Textfeld kann nicht editiert werden, man kann nur einen der auswählbaren Einträge angezeigt bekommen, sonst bleibt es leer.

Die ComboBox ist ein ItemControl und enthält daher die Eigenschaften der ItemsCollection. In XAML kann man die ComboBox so deklariert werden:

<ComboBox>
    <ComboBoxItem Content=”How I met your mother”/>
    <ComboBoxItem Content=”Two and a half men”/>
    <ComboBoxItem Content=”Big Bang Theory”/>
    <ComboBoxItem Content=”House, M.D.”/>
    <ComboBoxItem Content=”Bones”/>
</ComboBox>

Die Breite der ComboBox kann wie immer über Width bestimmt werden. Die oben angeführte Deklaration der Items kann über ein ein TextBlock mit dem gewünschten Inhalt zugewiesen werden. Das ist natürlich die bequemste Art, aber sie bietet kaum Flexibilität. Das ComboBoxItem könnte auch so deklariert werden:

<ComboBoxItem>tion
    <TextBlock>How I met your mother</TextBlock>
</ComboBoxItem>

Wie man vielleicht zu diesem Moment erkennen kann, ist das ComboBoxItem recht mächtig. Man kann anstelle des TextBlock jedes beliebige Control-Element einsetzen.

Die wichtigsten Event der ComboBox sind:

  • SelectionChanged (tritt ein, wenn der Anwender seine Auswahl trifft, also ein Element aus der Liste wählt bzw. seine Auswahl ändert)
  • DropDownOpen (tritt ein, wenn das Drop-Down-Fenster geöffnet wird)
  • DropDownClosed (tritt ein, wenn das Drop-Down-Fenster geschlossen wird)

ItemsCollection ist die Grundlage eines Item-Controls. Anstelle wie vorhin direkt in XAML aufgebaut werden oder man kann das Control-Element auch via Code befüllen.

<ComboBox x:Name=”CodeFilled” Loaded=”CodeFilled_Loaded”/>

Über das Loaded-Event wird die ComboBox schließlich befüllt.

 private void CodeFilled_Loaded(object sender, RoutedEventArgs e)
{
     CodeFilled.Items.Add(“New York”);
     CodeFilled.Items.Add(“Munich”);
     CodeFilled.Items.Add(“Vienna”);
     CodeFilled.Items.Add(“Paris”);
     CodeFilled.Items.Add(“Manchester”);
     CodeFilled.Items.Add(“Miami”);
     CodeFilled.SelectedIndex = 2;
 }

Die ItemsCollection wird dabei 6-mal mit eimen String-Eintrag befüllt. Und in der letzten Zeile wird der Eintrag mit der Indexnummer 2 (Vienna) als vorgewählten Eintrag festgelegt.

Aber hier sind noch nicht die Grenze der ItemsCollection, für eine solche Sammlung kann jedes Objekt infrage kommen, welches aus einer Collection besteht und das INotifyCollectionChanged Interface besitzt.  Eine Collection, die das Interface besitzt, bietet die Möglichkeit Änderungen einer Collection zu melden. Das ist deshalb notwendig, weil jede Änderung der Collection auch eine Änderung der ComboBox-Inhalte zu folge hat.

Die ObservableCollection-Klasse besitzt dieses Verhalten und kann damit als ItemCollection dienen. Man kann diese Collection verwenden in dem man die System.Collections.ObjectModel einbindet.

Man kann damit z.B. eine Klasse defnieren, die Books heißt und die eine Collection vom Typ Book ist. Die Klasse Books leitet sich von der Klasse ObserableCollection ab, damit man die entsprechende Schnittstelle zur Verfügung hat.

Hierfür legt man eine eigene Klasse an, die book.cs heißt und wie folgt definiert wird:

public class Book
{
    public String Titel { get; set; }
    public String Autor { get; set; }
    public String Verlag { get; set; }
}

Im XAML deklarieren wir die ComboBox und zusätzlich einen TextBlock, zur Ausgabe der Auswahl, wie folgt:

<ComboBox x:Name=”Collection” Loaded=”Collection_Loaded”/>
<TextBlock x:Name=”Display_Combo” Text=”NO” TextWrapping=”Wrap” Height=”35″ />

Die ComboBox muss jetzt mit Inhalten geladen werden:

        private void Collection_Loaded(object sender, RoutedEventArgs e)
        {
            ObservableCollection<Book> books = new ObservableCollection<Book>();

            books.Add(new Book()
            {
                Titel = “Silverlight 3: Crashkurs”,
                Autor = “Otto Fischer”,
                Verlag = “Microsoft Press”
            });
            books.Add(new Book() {
                  Titel=”Pro Silverlight 3 in C#”,
                  Autor=”Matthew MacDonald”,
                  Verlag=”Apress”});
            books.Add(new Book()
            {
                Titel = “Silverlight 3″,
                Autor = “Uwe Rozanski”,
                Verlag = “Mitp Verlag”
            });
            books.Add(new Book()
            {
                Titel = “Introducing Microsoft Silverlight 3″,
                Autor = “Laurence Moroney”,
                Verlag = “Microsoft Press”
            });
            books.Add(new Book()
            {
                Titel = “Das Affenpuzzle”,
                Autor = “David Harel”,
                Verlag = “Springer Verlag”
            });

            Collection.ItemsSource = books;
            Collection.DisplayMemberPath = “Titel”;
            Collection.SelectedIndex = 1;
            Collection.SelectionChanged += new SelectionChangedEventHandler(SelectionGeaendert);
        }

Als erstes instanzieren wir ein Object books und befüllen dies mit Informationen. Nachdem alle Objekte Buchtitel, Autor und Verlag haben, binden wir das Objekt mit der ComboBox und wählen, was angezeigt werden soll (in dem Fall der Titel).

Nach der Auswahl sollte natürlich auch was passieren, wenn ein Buchtitel gewählt wurde, dass geschieht in der letzten Zeile.

Der SelectionChanged-Event-Handler wird mit gibt schließlich den Buchtitel, Autor und Verlag  im PlugIn aus.
       
        private void SelectionGeaendert(object sender, SelectionChangedEventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            ItemCollection it = cb.Items;
            Book book = (Book)it[cb.SelectedIndex];
            Display_Combo.Text = book.Titel + “, ” + book.Autor + “, ” + book.Verlag;
        }

Hier wird im ersten Schritt wieder der sender gecastet, schließlich greift man auf die ItemCollection zu und wählt ein bestimmtes Item daraus aus. Da die Collection vom Typ Book ist, kann man auf Book casten und dies der lokalen Variable zuweisen.  Durch die Auswahl des Users wird der erhält man den zugehörigen Index über den Parameter SelectedIndex der ComboBox. Und über TextBlock werden alle Elemente des Buchobjekts ausgegeben.

In der Abbildung sieht man das Ergebnis, 3 Variante wie man eine ComboBox definieren kann.

In den o.a. Beispielen wurde aber nur einmal eine Ausgabe definiert.

Daily-Hour 30: Silverlight Steuerelement Teil 5: DatePicker

18. Februar 2010 juergen79 Keine Kommentare

Diesmal betrachten dir den DatePicker ich wollte herausfinden, was der Vorteil des DatePickers ist. Nun es braucht weniger Platz, da der Kalender ausklappt. Der Nachteil man kann nur ein Datum auswählen, aber in den meisten Fällen ist das ausreichend.

Der DatePicker ist wie der Calender teil der System.Windows.Control und muss genauso wie beim Control-Element Calender im Namespace definiert.

<StackPanel Height=”171″ Width=”184″>
       <TextBlock Text=”DatePicker” FontWeight=”Bold” FontSize=”16″ TextAlignment=”Center”/>
       <controls:DatePicker SelectedDateChanged=”DatePicker_SelectedDateChanged”/>
       <TextBlock Text=”Gewähltes Datum:”/>
       <TextBlock x:Name=”pickedDate” Text=”x”/>
</StackPanel>

Der Zugriff auf das ausgewählte Datum erfolgt, ebenso wie beim Kalender.

DatePicker date = (DatePicker)sender;
pickedDate.Text = date.SelectedDate.Value.ToLongDateString();

Zusätzlich kann man noch die Möglichkeit auf die beiden EventHandler CalenderOpen und CalenderClosed verwenden.

Daily-Hour 29: Silverlight Steuerelement Teil 4 – Calender

17. Februar 2010 juergen79 Keine Kommentare

Das Objekt Calender ist ein vollständiger Kalender, der User kann in dem Kalender blättern, ein Datum, einen Datumsbereich oder mehrere Datumsbereiche auswählen (abhängig von der Einstellung). In dem Objekt kann man auch Datumswerte von der Wahl ausnehmen oder die Wahl auf definierte Daten zu beschränken.

Um den Kalender im UserControl muss zu erst der Namespace definiert werden:

xmlns:controls=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls”

und dann kann man schließlich das Calender-Objekt einfügen:

<controls:Calendar />

Die Eigenschaften, die man dem Calender hinzufügen kann:

  • BlackoutDates (setzt nicht wählbare Datumswerte)
  • CalenderButtonStyle (definiert den Stil des CalenderButton)
  • CalenderItemStyle (definiert den Stil des CalenderItem)
  • DisplayDate (zeigt das DateTime-Objekt)
  • DisplayDateEnd (definiert das letzte anzuzeigende Datum)
  • DisplayDateStart (definiert das erste anzuzeigende Datum)
  • DisplayMode (definiert wie der Kalender angezeigt werden soll – Month, Year, Decade)
  • FirstDayOfWeek (legt fest mit welchem Tag die Woche beginnen soll – Standard: DayOfWeek.Sunday)
  • IsTodayHighlighted (liefert true zurück, falls das aktuelle Datum ausgewählt ist)
  • SelectedDate (liefert das ausgewählte Datum oder null – falls kein Datum gewählt ist – zurück)
  • SelectedDates (enthält ein oder mehrere Datumswerte, falls welche gewählt sind)
  • SelectionMode (erlaubt ob keine Ausder wahl – None -, eine Auswahl – SingleDate – oder mehrere Auswahlmöglichkeiten – MultipleRange – erlaubt sind.

DisplayMode

Month Year Decade

Als Standard ist die Variante Month definiert, da diese am häufigsten zum Einsatz kommt.

FirstDayOfWeek
Definiert mit welchem Wochentag die Woche im Kalender beginnen soll. Die Definition erfolgt über die englische Bezeichnung für den Tag bzw. über eine Zahl zwischen 0-6 (beginnend mit Sonntag).

Wird FirstDayOfWeek nicht angegeben so ist standardmässig der Montag als erster Wochentag angegeben.

Im Calender-Objekt wird der aktuelle Tag standardmässig hervorgehoben, soll dies deaktiviert werden, so kann man dies über die Eigenschaft IsTodayHighlighted=”False”.

Wie der Kalender aber benutzt werden kann, hängt von der Eigenschaft SelectionMode ab, wie vorhin erwähnt gibt es 4 Möglichkeiten. Das ausgewählte Datum bzw. die ausgewählten Wertebereiche können im Code dahinter abgefragt werden. Da eine Auswahl immer ein SelectedDateChanged-Event auslöst, kann man die ausgewählten Daten abfragen und im Code schließlich festlegen, welches Datumsformat zurückgegeben werden soll.

Und jetzt verwenden wir das was bisehr besprochen wurde:

 <StackPanel Orientation=”Horizontal”>
       <controls:Calendar DisplayMode=”Month” FirstDayOfWeek=”Sunday”
                       SelectionMode=”SingleDate” SelectedDatesChanged=”Calendar_SelectedDatesChanged”/>
       <TextBlock x:Name=”DisplayDate” Text=”Kein Datum ausgewählt!”/>
</StackPanel>

Und im Ereignis-Handler definieren wir folgende Zeilen:

Calendar cal = (Calendar)sender;
DisplayDate.Text = cal.SelectedDate.Value.ToShortDateString();

Als erstes wird das Objekt auf Calender gecastet und schließlich geben wir dem DisplayDate den Wert des ausgewählten Datum zurück. Es besteht die Möglichkeit den Wert als ToShortDateString() oder ToLongShortDateString().