locked
How can I build keyboard selecting action? RRS feed

  • Question

  • Hi Expression Blend Masters,

    I am working on a prototype of a touch screen device's UI, the item on the stage could be touched to select, and also they could be selected and choose by hard buttons. 

    So in this prototype, I need to make the item touch-able and ALSO I can use the arrow keys on the keyboard to move the indicator (the cyan rectangular ) item by item. How can I make the keyboard action works.

    Monday, April 2, 2012 11:42 PM

All replies

  • Hello Hao.

    I got to playing with your idea and came up with the following for a Silverlight application.  If you are doing WPF, it wouldn't be that hard to accomplish the same for WPF.

    ...

    I added a listbox to my project and filled it with buttons, much like your menu items.

    I then edited the ItemsPanelTemplate and changed the StackPanel to a WrapPanel.

    <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
    			<toolkit:WrapPanel KeyDown="ArrowKeySelection"/>
    		</ItemsPanelTemplate>

    I also added the KeyDown Event for the WrapPanel called ArrowKeySelection and created the KeyDown method in my code-behind.

    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace KeyBoardSelecting
    {
    	public partial class MainPage : UserControl
    	{
    		public MainPage()
    		{
    			InitializeComponent();
    		}
    		
    		private void ArrowKeySelection(object sender, System.Windows.Input.KeyEventArgs e)
    		{
    			int selected = myListBox.SelectedIndex;
    			
    			if (e.Key == Key.Left)
    			{
    				if ((selected != 0) && (selected != 3))
    					myListBox.SelectedIndex = selected - 1;
    			}
    			else if (e.Key == Key.Right)
    			{
    				if ((selected != 2) && (selected != 5))
    					myListBox.SelectedIndex = selected + 1;
    			}
    			else if (e.Key == Key.Up)
    			{
    				if (selected > 2)
    					myListBox.SelectedIndex = selected - 3;
    			}
    			else if (e.Key == Key.Down)
    			{
    				if (selected < 3)
    					myListBox.SelectedIndex = selected + 3;
    			}
    			e.Handled = true;
    		}
    
    		private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
    		{
    			myListBox.SelectedIndex = 0;
    		}
    	}
    }

    Then I edited my ItemContainerStyle so that when the item was selected it had the selection box as shown in your above image.

    Hope that helps and best of luck with your project.

    ~Christine

    .

    .

    .

    Here is the full Silverlight Xaml of my test project if you would like to test it.


    <UserControl
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" mc:Ignorable="d"
    	x:Class="KeyBoardSelecting.MainPage"
    	Width="369" Height="260" Loaded="UserControl_Loaded">
    	<UserControl.Resources>
    		<Style x:Key="MenuButton" TargetType="Button">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="Button">
    						<Grid>
    							<VisualStateManager.VisualStateGroups>
    								<VisualStateGroup x:Name="CommonStates">
    									<VisualState x:Name="Disabled"/>
    									<VisualState x:Name="Normal"/>
    									<VisualState x:Name="MouseOver"/>
    									<VisualState x:Name="Pressed">
    										<Storyboard>
    											<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
    										</Storyboard>
    									</VisualState>
    								</VisualStateGroup>
    							</VisualStateManager.VisualStateGroups>
    							<Rectangle x:Name="rectangle" Margin="5,5,10,10">
    								<Rectangle.Effect>
    									<DropShadowEffect Opacity="0.5"/>
    								</Rectangle.Effect>
    								<Rectangle.Fill>
    									<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    										<GradientStop Color="Silver" Offset="0"/>
    										<GradientStop Color="#FF919191" Offset="1"/>
    									</LinearGradientBrush>
    								</Rectangle.Fill>
    							</Rectangle>
    							<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="Menu Item"/>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
    			<toolkit:WrapPanel KeyDown="ArrowKeySelection"/>
    		</ItemsPanelTemplate>
    		<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
    			<Setter Property="Padding" Value="3"/>
    			<Setter Property="HorizontalContentAlignment" Value="Left"/>
    			<Setter Property="VerticalContentAlignment" Value="Top"/>
    			<Setter Property="Background" Value="Transparent"/>
    			<Setter Property="BorderThickness" Value="1"/>
    			<Setter Property="TabNavigation" Value="Local"/>
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="ListBoxItem">
    						<Grid Background="{TemplateBinding Background}">
    							<VisualStateManager.VisualStateGroups>
    								<VisualStateGroup x:Name="CommonStates">
    									<VisualState x:Name="Normal"/>
    									<VisualState x:Name="MouseOver"/>
    									<VisualState x:Name="Disabled">
    										<Storyboard>
    											<DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="contentPresenter"/>
    										</Storyboard>
    									</VisualState>
    								</VisualStateGroup>
    								<VisualStateGroup x:Name="SelectionStates">
    									<VisualState x:Name="Unselected"/>
    									<VisualState x:Name="Selected">
    										<Storyboard>
    											<DoubleAnimation Duration="0" To=".75" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColor2"/>
    											<DoubleAnimation Duration="0" To="5" Storyboard.TargetProperty="(Rectangle.RadiusX)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
    											<DoubleAnimation Duration="0" To="5" Storyboard.TargetProperty="(Rectangle.RadiusY)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
    											<ColorAnimation Duration="0" To="Cyan" Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
    											<DoubleAnimation Duration="0" To="3" Storyboard.TargetProperty="(Shape.StrokeThickness)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="SelectedUnfocused"/>
    								</VisualStateGroup>
    								<VisualStateGroup x:Name="FocusStates">
    									<VisualState x:Name="Focused">
    										<Storyboard>
    											<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
    												<DiscreteObjectKeyFrame KeyTime="0">
    													<DiscreteObjectKeyFrame.Value>
    														<Visibility>Visible</Visibility>
    													</DiscreteObjectKeyFrame.Value>
    												</DiscreteObjectKeyFrame>
    											</ObjectAnimationUsingKeyFrames>
    											<DoubleAnimation Duration="0" To="3" Storyboard.TargetProperty="(Shape.StrokeThickness)" Storyboard.TargetName="FocusVisualElement" d:IsOptimized="True"/>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="Unfocused"/>
    								</VisualStateGroup>
    								<VisualStateGroup x:Name="LayoutStates">
    									<VisualState x:Name="BeforeUnloaded"/>
    									<VisualState x:Name="BeforeLoaded"/>
    									<VisualState x:Name="AfterLoaded"/>
    								</VisualStateGroup>
    							</VisualStateManager.VisualStateGroups>
    							<Rectangle x:Name="fillColor" IsHitTestVisible="False" Opacity="0" RadiusY="5" RadiusX="5" Stroke="Cyan" StrokeThickness="5"/>
    							<Rectangle x:Name="fillColor2" Fill="{x:Null}" IsHitTestVisible="False" Opacity="0" RadiusY="1" RadiusX="1" Stroke="Black"/>
    							<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>
    							<Rectangle x:Name="FocusVisualElement" RadiusY="5" RadiusX="5" Stroke="Cyan" StrokeThickness="3" Visibility="Collapsed"/>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>	
    	</UserControl.Resources>
    
    	<Grid x:Name="LayoutRoot" Background="White">
    		<Grid Margin="10,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="350" Height="240">
    			<Rectangle Stroke="#FF929292" RadiusX="10" RadiusY="10" StrokeThickness="5"/>
    			<ListBox x:Name="myListBox" Margin="0" Width="330" Height="220" HorizontalAlignment="Center" VerticalAlignment="Center" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsPanel="{StaticResource ItemsPanelTemplate1}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" Background="{x:Null}" BorderBrush="{x:Null}">
    				<ListBox.ItemTemplate>
    					<DataTemplate>
    						<Grid Width="100" Height="100">
    							<Button Style="{StaticResource MenuButton}"/>
    						</Grid>
    					</DataTemplate>
    				</ListBox.ItemTemplate>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    				<Button Content="Button" Height="100" Style="{StaticResource MenuButton}" Width="100"/>
    			</ListBox>
    		</Grid>
    	</Grid>
    </UserControl>

    Tuesday, April 3, 2012 3:53 AM
  • Hello Christine,

    Thanks for helping! But I am having trouble in the very beginning step...:

    How can I "edited the ItemsPanelTemplate and changed the StackPanel to a WrapPanel." ?? I can't find where the option is.

    Thanks very much again!

    Hao

    Tuesday, April 3, 2012 5:24 PM
  • Hello Hao.

    Once you add your listBox to the project.

    1.  Right-Click it in the "Object and Timeline" panel.

    2.  Select Edit Additional Templates > Edit Layout of Items (Items Panel)

    3.  Edit a copy.

    4.  Give it a name or save the default that come up in the popup window.

    5.  Delete the VirtualizingStackPanel and replace it with a WrapPanel.

    <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
         <WrapPanel/>
    </ItemsPanelTemplate>

    Editing the templates can be a bit confusing at first but once you do a few you'll be an old pro. :)

    Let me know if you need any other help.

    ~Christine


    Tuesday, April 3, 2012 5:48 PM
  • Hi Christine,

    I am sorry to bordering you again .... but I still can't figure out the problem

    I don't have the option of "WrapPanel" in "Change Layout Type", if I change it directly in XAML, it said "The name "WarpPanel" does not exist in the namespace "http://schemas.microsoft.com/client/2007"


    • Edited by Hao Huang Tuesday, April 3, 2012 7:40 PM
    Tuesday, April 3, 2012 7:35 PM
  • Is this a Silverlight or WPF application?

    ~Christine

    Tuesday, April 3, 2012 7:47 PM
  • I did it as you advised in Silverlight. And also where is the "ItemContainerStyle " hidden?  Thank you!

    Tuesday, April 3, 2012 7:53 PM
  • Oh I see! what you were suggesting is in WPF.... Sorry about that! I will try it again
    Tuesday, April 3, 2012 7:58 PM
  • Ok for Silverlight you need to download the Toolkit.

    http://silverlight.codeplex.com/releases/view/43528

    Once you get it downloaded.  You will need to add a refrence to your project.

    My download is located at... C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\April 2010 Silverlight Toolkit\April 2010 Silverlight Toolkit\Bin

    The .dll file we want is... System.Windows.Controls.Toolkit.dll

    To add it to your project...

    1.  Right-Click on "Refrences" in your "Projects" panel.

    2.  Select "Add Refrence".

    3.  Navigate to System.Windows.Controls.Toolkit.dll and add it.

    4.  Rebuild your project and then the WrapPanel should be available to you.

    ~Christine

    If you prefer to work in WPF I am happy to provide a WPF example.

    Tuesday, April 3, 2012 8:01 PM
  • I did it as you advised in Silverlight. And also where is the "ItemContainerStyle " hidden?  Thank you!

    For ItemContainerStyle...

    Right-Click your list select Edit Additional Templates > Edit Generated Item Container (ItemContainerStyle)

    ~Christine

    Tuesday, April 3, 2012 8:04 PM