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