Controls - Daniel Greitens

Transcription

Controls - Daniel Greitens
Daniel Greitens, maximago GmbH
Steuerelemententwicklung
mit WPF / Silverlight / WP7
Inhalt dieser Session
• Praxisorientierte Steuerelement-Entwicklung
• Verschiedene Strategien zur Implementierung von Logik
und Visualisierung unter Berücksichtigung von:
•
•
•
•
•
Wartbarkeit
Performance
Konsistenz im UI
Effizienz in der Entwicklung
„Blendability“
2
Gemeinsamer Nenner für
WPF, SL und WP7
• Sehr ähnliche Technologie, aber…
• Gemeinsamer Code?
• MSDN: „Because of the differences between the XAML in
Silverlight and WPF, the following elements are harder to reuse:
•
Complex views (XAML)
•
Controls
•
Styling
•
Animation”
• Gemeinsame Vorgehensweise?
• Ja, Inhalt dieser Session.
3
Einführung
Steuerelemente im MVVM-Kontext
Interaktion
Steuerelemente
Views
ViewModels
Business-Objekte
Services
Datenfluss
5
Aufgaben von Steuerelementen
•
•
•
•
•
Datenanbindung
Übersetzung Daten zu Visualisierung
Übersetzung Interaktion zu Daten
Visualisierungssteuerung
Schichtentrennung Logik / Visualisierung
Soll-Ergebnis:
• Wartungsarmes User-Interface
• Konsistenz im User-Interface
• Effizienz in der Entwicklung
6
Beispiel
Grundstrategien
User Control
XAML + Code-Behind
Custom Control
Control
+
Templates
8
Grundstrategien
User Control
• Einfache
Implementierung
• Kann nicht erben
• Lässt sich erweitern
• Schlechte Performance
• Visualisierung hart mit
Logik verzahnt
• Referenzen auf XAMLElemente einfach
Custom Control
• Aufwendigere
Implementierung
• Kann erben
• Lässt sich erweitern
• Gute Performance
• Visualisierung in Template
separiert
• Referenzen auf XAMLElemente aufwendiger
9
KURZ-DEMO
User Control und Custom Control
DependencyProperty
• Registrierungssystem für Eigenschaften
• Überwacht deren Wert unter Berücksichtigung von u.a.:
• Bindings
• Animationen
• Standard-Werten
• Validierungsmechanismen
• Notwendig für:
• Animation der Eigenschaft
• DataBinding auf die Eigenschaft
• Auslagern eines Werts in Styles
• TemplateBinding in Templates
11
Erweiterungsmöglichkeiten
User Controls
• Ableitung und Erweiterung von User Control
• “it seems like WPF doesn't want us to do that.”
• Ergänzung eigener DependencyProperties in Code
Behind eines UserControls
• Zugriff auf Properties in XAML per…
• Element-Binding auf Root (WPF, SL und WP7)
• RelativeSource (nur WPF und ab SL5)
•
Tipp: Design-Time-Unterstützung in Blend per FallbackValue im Binding:
Text="{Binding Description, ElementName=UserControl, FallbackValue=Designtime-Anzeige}"
12
KURZ-DEMO
Erweiterung User Control
Aufbau Custom Control
• Abgeleitete Klasse (min. von FrameworkElement)
• Style (= ausgelagerte Eigenschaftswerte)
• Template (= ausgelagerter Gesamtaufbau)
• Styles und Templates ausgelagert in
Resource-Dictionaries
14
Auszug Vererbungskette
-
DependencyObject ,Visual, UIElement
-
FrameworkElement
-
-
-
Height, Width
-
Styling
-
FocusVisualStyle
Control
-
Template
-
Font-Properties
-
Alignment, Padding
-
Background, Border
ContentControl, TextBoxBase
-
-
ButtonBase
-
-
Content
Click-event
Button
ToggleButton
CheckBox
15
Styles
<Button Style=„{StaticResource MyButtonStyle}“ … />
<Resources>
<Style x:Key=„MyButtonStyle“ TargetType=„Button“>
<Setter Property=„Background“ Value="Red"/>
<Setter Property=„Width" Value=„25"/>
</Style>
</Resources>
Control-Template
<Button Content=„MyButton“>
<Button.Template>
<ControlTemplate TargetType=„{x:Type Button}“>
<Border>
<ContentPresenter/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Ablage des DefaultStyles in
„generic.xaml“
• Resource-Dictionary, das im Ordner „Themes“ im Root
der Class Library liegen muss
• Steuerelement-Klasse muss DefaultStyleKey setzen
• Aktivierung per ThemeInfo in AssemblyInfo in Class
Library (WPF, SL automatisch)
• Ressourcen werden dann automatisch bei Referenzierung
in anderen Projekten gezogen
• Theme-abhängige Resourcen möglich (z.B. Vista, XP)
• Ohne generic.xaml müssen alle Ressourcen manuell
eingebunden werden
18
Datenflug im Custom Control
ViewModel
DataBinding
{ Control }
TemplateParts
TemplateBinding
VisualStates
<Template />
19
Control-Template mit Template-Binding
<Button Content=„MyButton“ Background=„Red“>
<Button.Template>
<ControlTemplate TargetType=„{x:Type Button}“>
<Border Background=„{TemplateBinding Background}“>
<ContentPresenter/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Control-Template mit Template-Binding
<Button Content=„MyButton“ Background=„Red“>
<Button.Template>
<ControlTemplate TargetType=„{x:Type Button}“>
<Border Background=„{TemplateBinding Background}“ >
<ContentPresenter/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
• Tipp: Converter im TemplateBinding: TemplateBinding auf
„DataContext“ und reines DataBinding mit Converter auf die
Eigenschaft.
Besonderheit: Eigenschaft „Content“
• DependencyProperty vom Typ object
• Kann ein einzelnes UI-Element aufnehmen
• Definition des XML-Kinds per Klassen-Attribut
„ContentProperty“
• Weitere Kindselemente in Blend per
„AlternateContentProperty“
• Automatisches TemplateBinding durch ContentPresenter
• Tipp: ContentControl für Definition von
Eigenschaften für Inhaltselement
Tipp: AlternateContentProperty in WPF im Namespace
Microsoft.Windows.Design.PropertyEditing
(Microsoft.Windows.Design.Interaction.dll)
22
DEMO Custom Control
- Form-Element
TemplatePart
• Referenziert im Control auf ein UI-Element im Template
• Klassen-Attribut zur Darstellung in Expression Blend
• WPF-Konvention: Benennung mit vorgestelltem „PART_“
• Einsatzgebiete:
• Mit Bedacht, da enge Verzahnung von Logik mit
Visualisierung. Häufig durch TemplateBinding
ersetzbar!
• Wenn auf Events von UI-Elementen reagiert
werden soll
• Wenn Eigenschaften nicht public sein sollen
24
DEMO Custom Control
- Form-Element mit Hilfe-Popup
Zwischenzusammenfassung
• User Control
•
Einfachere Implementierung
•
Feste Verzahnung von Logik und Visualisierung
•
Kann nicht erben
•
Schlechte Performance
• Custom Control
•
Aufwendige Implementierung
•
Separierte Visualisierung
•
Gute Performance
•
Generic.xaml
•
TemplateBinding schleust Werte von Instanz zu Template
•
TemplatePart gewährt Zugriff von Instanz zu Element in Template
26
Konzepte zur Steuerung der
Visualisierung
eines Custom Controls
Eine Logik, verschiedene
Visualisierungen
• Kapselung von verschiedenen Visualisierungen
für ein und dasselbe Steuerelement
• Beeinflussung der ganzen Visualisierung durch Setzen eines
einzigen Eigenschaftswerts in XAML
= Vorteile: Sehr saubere Views, konsistentes Design,
weniger Arbeit für Entwickler
- Nachteil: Bei Änderung der Logik erhöhter Test-Aufwand
28
Eine Logik, verschiedene
Visualisierungen
• Konditionelle Veränderung von Werten
im Style per Trigger
• Konditionelles Switchen von ganzen
Templates im Style per Trigger
Nur WPF
29
DEMO Trigger
Form-Element mit 2 Templates
Eine Logik, verschiedene
Visualisierungen
• Konditionelle Veränderung von Werten
im Style per Trigger
• Konditionelles switchen von ganzen
Templates im Style per Trigger
Nur WPF
• Verändern von Werten im Template
per VisualStates
WPF, SL und WP7
31
Custom Visual States
• Visual States werden durch Logik in Klasse aktiviert
• Design der einzelnen States in Template definiert
• Visual States werden per Klassen-Attribut durch
Blend im Template erzeugt
• Automatisch Übergänge = Erhebliche Effizienz
im Design!
• Keine Ausnahme wenn Visual State nicht in XAML definiert
• Tipp: VisualStates stehen im Code erst
• in „OnApplyTemplate“ zur Verfügung!
32
DEMO
- Form-Element mit 2 States
Nebenschauplätze
Steuern des Gestaltungsspielraums
von Steuerelementen
• Zentral / Einschränkung der Anpassbarkeit
•
Implementierung: Wenig Template-Binding
•
= Gesteuerte/Eingeschränkte „Themability“
•
= Konsistentes Design
•
= Hohe Entwickler-Produktivität
•
Beispiel: Software-UI
• Dezentral / Maximale Anpassbarkeit
•
Implementierung: Viel Template-Binding
•
= Leichte „Themability“
•
= Hohe Wiederverwendbarkeit
•
Beispiel: Anbieter von Steuerelementen
35
Blendability
• Parameterloser Konstruktor für Instanziierung per XAML
• DependencyProperties immer mit DefaultValue
• Steuerelemente nie mit Business-Logik, DatenVerbindungen oder sonstigen Abhängigkeiten
• Design-Time-Datenkontext mit d: in Blend einbinden
• Erkennung der Design-Time:
#if SILVERLIGHT
_isInDesignMode = DesignerProperties.IsInDesignTool;
#else
var prop = DesignerProperties.IsInDesignModeProperty;
_isInDesignMode = (bool)DependencyPropertyDescriptor
.FromProperty(prop, typeof(FrameworkElement))
.Metadata.DefaultValue;
#endif
36
Einfache Design Time Features
• Category-Attribut
• Default-Intitializer
• Und, und, und…
37
Was Sie tun sollten:
• Code-Behind nur marginal nutzen (z.B. für Events)
• Niemals aus Code-Behind eines User Controls hart auf UIElemente im XAML referenzieren
• Steuerelemente meist als Custom Control implementieren
• Steuerelemente niemals per Code in VisualTree hängen! Sondern
Datenobjekte mit Datatemplates o.ä.
• Kein DataBinding in Styles und Templates
• Nutzen Sie Expression Blend!
• Keine überflüssigen Attribute in View setzen
• Keine Design-Attribute in View setzen, gehören in Style oder
Template
• Separieren Sie Controls und Resources
in eigene Assemblies
• Immer implizite DefaultStyles, nur
bewusst explizit in XAML setzen
38