Showing Progress, Changing State
In Windows Store Apps verwende ich oft Services – bei denen es (auch unter Windows Azure) etwas dauern kann bis eine Antwort da ist. Mit der ProgressBar und dem ProgressRing kann diese Dauer für den User einfach dargestellt werden. Oft habe ich aber im User Interface nicht nur einen State für „in-progress“, sondern oft auch andere States wie „EditMode“ und „ReadMode“. Solche States einfach zu wechseln geht mit Hilfe der VisualStateManager Klasse. In diesem Blog-Artikel zeige ich ein paar Hilfsmittel dafür.
Image © Petr Balik
Dreamstime.com
Zuerst die ProgressBar. Dieses Element ist aber nicht sichtbar eingestellt. Sichtbar wird die ProgressBar erst mit einem Statewechsel.
<ProgressBar x:Name="progressBar" IsIndeterminate="True" Visibility="Collapsed" HorizontalAlignment="Stretch" />
Um den State-Wechsel vom Progress-Mode zurück nicht zu vergessen, und auch mich bei den Namen der States nicht zu vertippen habe ich mir eine Hilfsklasse geschrieben – VisualStateModeChanger. In der Page selbst definiere ich eine Enumeration der Page-States, z.B.
private enum PageMode { NormalMode, SelectionMode, EditMode, ProgressMode, SelectionProgressMode }
Im Konstruktor der Page-Klasse erzeuge ich eine Instanz vom VisualStateModeChanger der mit der Enumeration und der Page Instanz erzeugt wird:
this.pageModeChanger = new VisualStateModeChanger<PageMode>(this);
Im Event Handler kann ich jetzt einfach den State wechseln. Der VisualStateModeChanger startet hier mit dem ProgressMode und stellt nach dem Aufruf des Service-Calls mit Aufruf der Dispose Methode auf den NormalMode um:
using (this.pageModeChanger.GotoStateFromTo(PageMode.ProgressMode, PageMode.NormalMode)) { // make the async call to the service... }
Ganz einfach. Jetzt brauchen wir noch noch die Implementierung vom VisualStateModeChanger. GoToState wechselt direkt in einen anderen State, GoToStateFromTo startet mit dem fromState und wechselt mit disposing in den toState.
public class VisualStateModeChanger<T> where T : struct { private Control control; private T currentMode; public VisualStateModeChanger(Control control) { this.control = control; } public void GotoState(T newState) { VisualStateManager.GoToState(control, Enum.GetName(typeof(T), newState), useTransitions: true); currentMode = newState; } public IDisposable GotoStateFromTo(T fromState, T toState) { VisualStateManager.GoToState(control, Enum.GetName(typeof(T), fromState), useTransitions: true); return new VisualStateDisposer<T>(control, toState); } public T CurrentMode { get { return currentMode; } } private class VisualStateDisposer<T1> : IDisposable where T1 : struct { private Control control; private T1 endState; public VisualStateDisposer(Control control, T1 endState) { this.control = control; this.endState = endState; } public void Dispose() { VisualStateManager.GoToState(control, Enum.GetName(typeof(T1), endState), useTransitions: true); } } }
Jetzt muß nur noch im XAML definiert werden was beim State-Wechsel passiert. In diesem Beispiel wird beim Wechsel in den ProgressMode die progressBar auf Visible umgestellt.
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CustomStates"> <VisualState x:Name="ProgressMode"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="progressBar"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState>
Was bei den State-Wechsel passiert, dafür kann Blend zu Hilfe genommen werden – und Animationen bei den Statewechsel definiert.
Christian
Weitere Infos zu Windows Store Apps in meinen Workshops und im Buch Professional C# 2012.
From → Windows Store Apps