Silverlight 2: Controls für WPF und Silverlight in einer Bibliothek entwickeln

Eine der am häufigsten gestellten Fragen zu Silverlight ist: “Kann man Controls sowohl für Silverlight als auch für WPF gleichzeitig entwickeln”. Und die klare Antwort lautet: Ja, man kann.

Dazu ist allerdings ein kleiner Trick notwendig. Man kann leider nicht die gleiche dll für WPF und Silverlight verwenden. Silverlight verwendet einen eigenen Compiler und kann auch keine “normalen” dlls aufnehmen die das .NET Framework mitbringt.

Wie bekommt es nun hin das man Code und Controls, den man selbstverständlich nur einmal schreiben möchte, sowohl in WPF- und Silverlight-Anwendungen einbetten kann?

Ganz einfach.

1. Eine normale Windows Class Library / Klassenbibliothek erstellen.

image

In dieser fügt man nun die neuen Controls/Steuerelemente ein die man gerne für beide Zielplattformen (WPF und Silverlight) verwenden möchte. In meinem Fall sind das zwei Controls: LabeledTextBox und FeedbackControl. Das FeedbackControl beinhaltet wiederum drei mal die LabeledTextBox.

2. WPF User Control erstellen

image

Sofort nach dem Visual Studio mir das neue Control (LabeledTextBox) erstellt hat, sehe ich mit schrecken, wie viele Usings überhaupt im Code sind.

image

Das Problem daran ist, das Silverlight den Namespace System.Windows.Navigation nicht kennt, aber denn brauchen wir sowieso nicht. Daher bitte alle nicht benötigten Usings rauswerfen mit folgenden Trick:

image

Ungeschlagen mein Favorit an kleinen Helfern in Visual Studio. Denn nachdem ich nun alle nicht benötigten Usings rausgeworfen habe, bleibt folgendes übrig.

image

Wow. Nur noch ein Namespace wird importiert.

Der Code für meine LabeledTextBox sieht wie folgt aus:

    1: public partial class LabeledTextBox : UserControl
    2: {
    3:     public LabeledTextBox()
    4:     {
    5:         InitializeComponent();
    6:  
    7:         CheckText();
    8:         _value.TextChanged += new TextChangedEventHandler(_value_TextChanged);
    9:     }
   10:  
   11:     void _value_TextChanged(object sender, TextChangedEventArgs e)
   12:     {
   13:         CheckText();
   14:     }
   15:  
   16:     private void CheckText()
   17:     {
   18:         if (IsRequired && _value.Text.Length ==  0)
   19:         {
   20:             _warning.Visibility = System.Windows.Visibility.Visible;
   21:         }
   22:         else
   23:         {
   24:             _warning.Visibility = System.Windows.Visibility.Collapsed;
   25:         }
   26:     }
   27:  
   28:     private bool _isRequired = true;
   29:  
   30:     public bool IsRequired
   31:     {
   32:         get { return _isRequired; }
   33:         set { _isRequired = value; CheckText(); }
   34:     }
   35:  
   36:     public string LabelText
   37:     {
   38:         get { return _label.Text; }
   39:         set { _label.Text = value; }
   40:     }
   41:  
   42:     public string Text
   43:     {
   44:         get { return _value.Text; }
   45:         set { _value.Text = value; }
   46:     }
   47:  
   48:     public string Warning
   49:     {
   50:         get { return _warning.Text; }
   51:         set { _warning.Text = value; }
   52:     }
   53: }

Das Design habe ich mit Expression Blend erstellt:

image image

3. Aufbau der Silverlight / WPF – MixedMode Projektstruktur

image

Um nun die WPF Controls in Silverlight integrieren zu können, legt man ein neues Silverlight Class Library Projekt an. (Oliver.Demos.Controls.Silverlight).

Anschließend fügt man den gewünschten Code (XAML- + Codebehind-Datei) mittels hinzufügen eines bereits existieren Elements als LINK zum Projekt hinzu.

image

Dadurch kopiert man nicht den Sourcecode aus dem anderen Projekt, sondern erhält eine Referenz. Das bedeutet, das man den Code nur an einer Stelle pflegt und bei Änderungen nicht an allen referenzierten Stellen nachpflegen muss.

4. Anlegen der Clients für WPF und Silverlight

Der WPF Client erhält einen Referenz-Verweis auf das “normale” Class Library Projekt und der Silverlight Client einen Verweis auf die Silverlight-Variante mit den Referenzen.

Wenn man dann die Solution kompiliert, stehen einem im Blend die neuen Controls zur Verfügung. Änderungen an der Haupt-Control-Bibliothek werden sofort dann in die WPF- und Silverlight-Clients übernommen

Das Originalfeedback-Control in Blend

image

Das Control im WPF Projekt in Blend und im Browser

image image

Das gleiche Control in Silverlight in Blend und im Browser

image  image

Das vollständige Projekt gibt es hier zum Downloaden