Optimierung eines Controls für Maus und Touch in einer WinStore App

23. August 2013

Spätestens seit der Einführung von Windows 8 bekommt das Thema Touch eine immer größere Bedeutung in der Entwicklung von Applikationen. Und dennoch sind Nutzer immer noch die Eingabe per Maus und Tastatur gewohnt. Abseits von technischen Fragestellungen (kann der Bildschirm überhaupt Touch?), ist es daher wichtig das Design einer App nicht ausschließlich auf den Input per Touch auszurichten.

Daher haben wir für unsere App Worktime Pro ein Control entwickelt, welches versucht beide Formen des Inputs zu vereinen und den Nutzer optimal durch den Dialog zu leiten. Im folgenden Artikel möchte ich die Motivation, das Design und die technische Umsetzung des Controls beschreiben.

Ein umständliches Touch-Control

Ausgangspunkt unserer Entwicklung war ein Control, mit dem der Nutzer eine Uhrzeit eingeben kann. In der ursprünglichen Version war die Auswahl dieser lediglich durch Scrollen und Klicken möglich. Das Design orientierte sich dabei an ähnlichen Controls, die sich häufig in Smartphones finden lassen. Eine Eingabe über die Tastatur war leider nicht möglich, das Springen per Tab in die nächste Zelle somit auch überflüssig. Der Nutzer die gewünschte Uhrzeit folglich nur per Mausklick setzen.

clip_image001clip_image002

Ein neuer Ansatz

Aufgrund der Rückmeldungen der Nutzer haben wir uns entschieden, das Control zu verbessern. Die Anforderungen hierbei waren:

· Beim Input per Touch bleibt das Verhalten wie beschrieben

· Beim Nutzen der Maus oder Tastatur durch den Anwender soll eine Textbox zur Eingabe der Zeit (dienen)

Dieser Ansatz war für unsere App neu, da bisher kein Control abhängig von der Art des Inputs reagierte. Dennoch war dies aus unserer Sicht der einzige Weg, beide Nutzergruppen mit derselben App ansprechen zu können. Sowohl für geübte Nutzer, die per Tab und einfacher Zahleneingabe ihre Zeiteinträge machen wie auch für Nutzer ohne (Hardware-)Tastatur sollte es einfach sein, die gewünschte Zeit auszuwählen.

Die Umsetzung

Für die technische Umsetzung ist es natürlich zunächst wichtig herauszufinden, in welchem Kontext sich der Nutzer bewegt. Dazu bieten die Events in WinRT die geeigneten Informationen. Für unser Control ist die Unterscheidung nur relevant, sobald der Nutzer mit dem Control interagiert. Die passive Anzeige der gewählten Uhrzeit ist in allen Fällen gleich. Für die Unterscheidung benutzen wir einen EventHandler des OnPointerEntered-Events. In den EventArgs finden wir dann die nötige Information.

   1: private void TimePickerGrid_OnPointerEntered(object sender, PointerRoutedEventArgs e)

   2: {

   3:     if (e.Pointer.PointerDeviceType == PointerDeviceType.Touch ||

   4:         e.Pointer.PointerDeviceType == PointerDeviceType.Pen)

   5:     {

   6:         this.GoIntoTouchMode();

   7:     }

   8:     else

   9:     {

  10:         this.GoIntoMouseMode();

  11:     }

  12: }

In den Methoden GoIntoTouchMode() und GoIntoMouseMode() kann man nun die nötigen Manipulationen durchführen. In unserem Fall haben beide Eingabemethoden jeweils eigene Controls, deren Sichtbarkeit je nach Bedarf an- oder abgeschaltet wird. Da die angezeigte Zeit unabhängig von der Bedienart ist, muss beim Verlassen des Controls nichts mehr getan werden.

Alternativ zum Setzen der Property “Visibility” ließe sich das Verhalten auch über VisualStates steuern. Dies hat den Vorteil, dass sich das Pattern dann leichter in anderen Controls mit einer ähnlichen Fragestellung wiederverwenden lässt. Im oben gezeigten EventHandler würde dann direkt der jeweilige VisualState gesetzt.

   1: <Grid x:Name="TimePickerGrid" 

   2:           HorizontalAlignment="Stretch" 

   3:           MinHeight="30" 

   4:           PointerEntered="TimePickerGrid_OnPointerEntered">

   5:         <TextBox Visibility="Collapsed" 

   6:                  x:Name="TimeTextBox"

   7:                  GotFocus="TimeTextBox_OnPointerPressed"

   8:                  Text="{Binding TimeAsString, Mode=TwoWay}"

   9:                  BorderThickness="{Binding BorderThickness, ElementName=ControlRoot}"

  10:                  HorizontalAlignment="Stretch"

  11:                  VerticalAlignment="Stretch"

  12:                  MaxLength="6"

  13:                  InputScope="Number"

  14:                  Style="{Binding TextBoxStyle}"/>

  15:         <ToggleButton Content="{Binding TimeAsString}" 

  16:                 BorderThickness="{Binding BorderThickness, ElementName=ControlRoot}"

  17:                 x:Name="TimeButton"

  18:                 HorizontalAlignment="Stretch"

  19:                 VerticalAlignment="Stretch"

  20:                 Style="{Binding ButtonStyle}"/>

  21:         <Popup x:Name="PickerPopup" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="{Binding IsChecked, ElementName=TimeButton, Mode=TwoWay}" IsLightDismissEnabled="True">

  22:             <!-- XAML für Touch input --> 

  23:         </Popup>

  24:     </Grid>