head.WriteLine()

Freitag, Mai 20, 2011

TT.UIA: Behaviors

Wie hier bereits beschrieben, haben Expression Blend Behaviors gegenüber Attached Properties einige Vorteile. Hierzu zählt vor allem die Designer-Unterstützung in Blend. Ein weiterer Vorteil ist jedoch auch die Tatsache, dass Behaviors mit mehreren Elementen verbunden werden können.
Ein einfaches Beispiel:Ein Dialog enthält eine Textbox/Button-Kombination zur Auswahl einer Datei.
OpenFileBehavior
Klassischerweise würde man hier im Code-Behind den Dateidialog öffnen und die Auswahl in die daneben stehende Textbox übertragen. Da dies eine Funktionalität ist, die häufiger benötigt wird, bietet es sich an sie zu kapseln. Der Code-Behind-Ansatz ist jedoch auch in MVVM-Szenarien ein Problem. Das Öffnen des Dialogs möchte man jedoch auch nicht im ViewModel hinterlegen, da es sich um UI-Code handelt.

Das Open File Behavior

Mit einem Behavior lässt sich solch eine Funktionalität sehr komfortabel abbilden. TT.UIA bietet hierfür die Klasse OpenFileBehavior. Sie leitet von TargettetTriggerAction<T> ab und kann somit nicht nur ein Element (der Button im oberen Beispiel), sondern auch an ein Zielelement (die Textbox) gebunden werden.
...
<Button
  xmlns:i=
    "clr-namespace:System.Windows.Interactivity;
    assembly=System.Windows.Interactivity"
  xmlns:behaviors=
    "clr-namespace:Thinktecture.UIAnnotations.Behaviors;
     assembly=Thinktecture.UIAnnotations">

  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <behaviors:OpenFileBehavior
        TargetName="imageTextBox"
        DialogTitle="Select an image..."
        Filter="PNG Files|*.png" />
    </i:EventTrigger>
  </i:Interaction.Triggers>

</Button>

<TextBox x:Name="imageTextBox" />
...

Die Deklaration erfolgt hierbei über die Klasse System.Windows.Interactivity.Interaction, die Teil des Expression Blend SDKs ist.

Das Busy Behavior

Ein weiteres Problem in MVVM-Anwendungen ist der Umgang mit Cursorn und anderen Fortschrittsanzeigen. Denn das ViewModel sollte weder explizit einen Cursors setzen, noch ein entsprechendes UI-Element direkt steuern. In Silverlight löst man dies meist mit dem beliebten (wenn auch hässlichen) BusyIndicator, die per Data Binding an das ViewModel gebunden wird. Hierfür muss die Komponente jedoch zur Entwurfszeit in das Layout des jeweiligen Fensters so eingefügt werden, dass sie im Vordergrund steht. Dies verursacht bei nachträglichen Layout-Änderungen häufig Probleme. Zudem sollte die Bedienung des Fensters verhindert werden, sobald der BusyIndicator aktiv wird.
All diese Herausforderungen versucht die Klasse *BusyBehavior* zu lösen. Sie zeigt eine überdimensionale Eieruhr und legt dabei einen Overlay über das zugehörige Fenster um die Bedienung der Oberfläche durch den Benutzer zu verhindern. Das Busy Behavior kann mit einem beliebigen Element verknüpft werden. Es ermittelt zur Laufzeit das übergeordnete Fenster und fügt sich auf oberster Ebene in den visuellen Baum ein.
<i:Interaction.Behaviors>
  <behaviors:BusyBehavior
    IsBusy="{Binding IsBusy}" />
</i:Interaction.Behaviors>

Die Steuerung erfolgt über die Eigenschaft *IsBusy*, die zum Beispiel an eine entsprechende Eigenschaft des zugehörigen ViewModels gebunden werden kann. Das Ganze sieht dann zur Laufzeit in etwas so aus:
BusyBehavior

Das Dialog Button Behavior

Die Klasse DialogButtonBehavior steuert das Verhalten von Dialogschaltflächen. Klassischerweise hat ein Dialog einen Accept- und einen Cancel-Button, womit der Benutzer das Fenster mit Enter bestätigen, bzw. mit ESC abbrechen kann. Hierbei wird das Fenster geschlossen und die DialogResult-Eigenschaft entsprechend gesetzt. All dies fasst DialogButtonBehavior zusammen, wie das folgende Beispiel zeigt:
<Button>
  <i:Interaction.Behaviors>
    <behaviors:DialogButtonBehavior ButtonType="Ok" />
  </i:Interaction.Behaviors>
</Button>

Über die Eigenschaft ButtonType kann das entsprechende Verhalten definiert werden.

Das Focus Behavior

Die Klasse FocusBehavior markiert das fokussierte Eingabeelement mit einer beliebigen Hintergrundfarbe.
<TextBox>
  <i:Interaction.Behaviors>
    <behaviors:FocusBehavior HighlightBrush="Yellow" />
  </i:Interaction.Behaviors>
</TextBox>

FocusBehavior
So, das war’s erstmal mit den Behaviors von TT.UIA. Im nächsten Post gehe ich auf die Behavior Factories ein, mit denen einige Limitationen der Behaviors behoben werden können.

Labels: