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.
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
Sofort nach dem Visual Studio mir das neue Control (LabeledTextBox) erstellt hat, sehe ich mit schrecken, wie viele Usings überhaupt im Code sind.
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:
Ungeschlagen mein Favorit an kleinen Helfern in Visual Studio. Denn nachdem ich nun alle nicht benötigten Usings rausgeworfen habe, bleibt folgendes übrig.
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:
3. Aufbau der Silverlight / WPF – MixedMode Projektstruktur
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.
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
Das Control im WPF Projekt in Blend und im Browser
Das gleiche Control in Silverlight in Blend und im Browser
Das vollständige Projekt gibt es hier zum Downloaden