Skip to main content

Microsoft Silverlight

Answered Question AutoCompleteBox: implementing page/up down in popupRSS Feed

(0)

kobruleht
kobruleht

Member

Member

161 points

579 Posts

AutoCompleteBox: implementing page/up down in popup

I'm looking for a way to implement page up/down navigation in popup in SL3

I tried sample solution from

http://www.jeff.wilcox.name/2008/12/pageup-pagedown

buto got exception below. How to add page up/down ctrl+home/end  navigation to AutoCompleteBox ?

Andrus.

 

System.Windows.Markup.XamlParseException occurred
  Message=" [Line: 0 Position: 0]\r\n   --- Inner Exception ---\r\nElement is already the child of another element.\r\n"
  LineNumber=0
  LinePosition=0
  StackTrace:
       at MS.Internal.XcpImports.MethodEx(IntPtr ptr, String name, CValue[] cvData)
  InnerException: System.InvalidOperationException
       Message="Element is already the child of another element."
       StackTrace:
            at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
            at MS.Internal.XcpImports.Collection_AddValue[T](PresentationFrameworkCollection`1 collection, CValue value)
            at MS.Internal.XcpImports.Collection_AddDependencyObject[T](PresentationFrameworkCollection`1 collection, DependencyObject value)
            at System.Windows.PresentationFrameworkCollection`1.AddDependencyObject(DependencyObject value)
            at System.Windows.Controls.UIElementCollection.AddInternal(UIElement value)
            at System.Windows.PresentationFrameworkCollection`1.Add(T value)
            at Microsoft.Windows.Controls.AutoCompleteBox.OnApplyTemplate()
            at CustomAutoCompleteBox.CustomizedAutoCompleteBox.OnApplyTemplate()
            at System.Windows.FrameworkElement.OnApplyTemplate(IntPtr nativeTarget)
       InnerException:

Mog Liang - MSFT
Mog Lian...

All-Star

All-Star

15884 points

1,541 Posts

Answered Question

Re: AutoCompleteBox: implementing page/up down in popup

Hi,

You could find autocompletebox inner listbox by accessing its default template, then by handling autocomplatebox keydown event, you could set selectedindex on listbox.

sample code:

xaml 

	<UserControl.Resources>
		<ControlTemplate x:Key="CommonValidationToolTipTemplate" TargetType="ToolTip">
			<Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0">
				<VisualStateManager.VisualStateGroups>
					<VisualStateGroup x:Name="OpenStates">
						<VisualStateGroup.Transitions>
							<VisualTransition GeneratedDuration="0"/>
							<VisualTransition GeneratedDuration="0:0:0.2" To="Open">
								<Storyboard>
									<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="Translation" Storyboard.TargetProperty="X" To="0">
										<DoubleAnimation.EasingFunction>
											<BackEase Amplitude=".3" EasingMode="EaseOut"/>
										</DoubleAnimation.EasingFunction>
									</DoubleAnimation>
									<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1"/>
								</Storyboard>
							</VisualTransition>
						</VisualStateGroup.Transitions>
						<VisualState x:Name="Closed">
							<Storyboard>
								<DoubleAnimation Duration="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0"/>
							</Storyboard>
						</VisualState>
						<VisualState x:Name="Open">
							<Storyboard>
								<DoubleAnimation Duration="0" Storyboard.TargetName="Translation" Storyboard.TargetProperty="X" To="0"/>
								<DoubleAnimation Duration="0" Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1"/>
							</Storyboard>
						</VisualState>
					</VisualStateGroup>
				</VisualStateManager.VisualStateGroups>
				<Grid.RenderTransform>
					<TranslateTransform x:Name="Translation" X="-25"/>
				</Grid.RenderTransform>
				<Border Margin="4,4,-4,-4" Background="#052A2E31" CornerRadius="5"/>
				<Border Margin="3,3,-3,-3" Background="#152A2E31" CornerRadius="4"/>
				<Border Margin="2,2,-2,-2" Background="#252A2E31" CornerRadius="3"/>
				<Border Margin="1,1,-1,-1" Background="#352A2E31" CornerRadius="2"/>
				<Border Background="#FFDC000C" CornerRadius="2">
					<TextBlock Margin="8,4,8,4" MaxWidth="250" UseLayoutRounding="false" Foreground="#FFFFFFFF" Text="{Binding (Validation.Errors)[0].Exception.Message}" TextWrapping="Wrap"/>
				</Border>
			</Grid>
		</ControlTemplate>
		<Style x:Key="AutoCompleteBoxStyle1" TargetType="input:AutoCompleteBox">
			<Setter Property="IsTabStop" Value="False"/>
			<Setter Property="Padding" Value="2"/>
			<Setter Property="BorderThickness" Value="1"/>
			<Setter Property="BorderBrush">
				<Setter.Value>
					<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
						<GradientStop Color="#FFA3AEB9" Offset="0"/>
						<GradientStop Color="#FF8399A9" Offset="0.375"/>
						<GradientStop Color="#FF718597" Offset="0.375"/>
						<GradientStop Color="#FF617584" Offset="1"/>
					</LinearGradientBrush>
				</Setter.Value>
			</Setter>
			<Setter Property="Background" Value="#FFFFFFFF"/>
			<Setter Property="Foreground" Value="#FF000000"/>
			<Setter Property="MinWidth" Value="45"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="input:AutoCompleteBox">
						<Grid Opacity="{TemplateBinding Opacity}">
							<VisualStateManager.VisualStateGroups>
								<VisualStateGroup x:Name="PopupStates">
									<VisualStateGroup.Transitions>
										<VisualTransition GeneratedDuration="0:0:0.1" To="PopupOpened"/>
										<VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed"/>
									</VisualStateGroup.Transitions>
									<VisualState x:Name="PopupOpened">
										<Storyboard>
											<DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="1.0"/>
										</Storyboard>
									</VisualState>
									<VisualState x:Name="PopupClosed">
										<Storyboard>
											<DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="0.0"/>
										</Storyboard>
									</VisualState>
								</VisualStateGroup>
								<VisualStateGroup x:Name="ValidationStates">
									<VisualState x:Name="Valid"/>
									<VisualState x:Name="InvalidUnfocused">
										<Storyboard>
											<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
												<DiscreteObjectKeyFrame KeyTime="0">
													<DiscreteObjectKeyFrame.Value>
														<Visibility>Visible</Visibility>
													</DiscreteObjectKeyFrame.Value>
												</DiscreteObjectKeyFrame>
											</ObjectAnimationUsingKeyFrames>
										</Storyboard>
									</VisualState>
									<VisualState x:Name="InvalidFocused">
										<Storyboard>
											<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
												<DiscreteObjectKeyFrame KeyTime="0">
													<DiscreteObjectKeyFrame.Value>
														<Visibility>Visible</Visibility>
													</DiscreteObjectKeyFrame.Value>
												</DiscreteObjectKeyFrame>
											</ObjectAnimationUsingKeyFrames>
											<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
												<DiscreteObjectKeyFrame KeyTime="0">
													<DiscreteObjectKeyFrame.Value>
														<System:Boolean>True</System:Boolean>
													</DiscreteObjectKeyFrame.Value>
												</DiscreteObjectKeyFrame>
											</ObjectAnimationUsingKeyFrames>
										</Storyboard>
									</VisualState>
								</VisualStateGroup>
							</VisualStateManager.VisualStateGroups>
							<TextBox x:Name="Text" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Foreground="{TemplateBinding Foreground}" IsTabStop="True" Padding="{TemplateBinding Padding}" Margin="0" Style="{TemplateBinding TextBoxStyle}"/>
							<Border x:Name="ValidationErrorElement" Visibility="Collapsed" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1">
								<ToolTipService.ToolTip>
									<ToolTip x:Name="validationTooltip" Template="{StaticResource CommonValidationToolTipTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
										<ToolTip.Triggers>
											<EventTrigger RoutedEvent="Canvas.Loaded">
												<BeginStoryboard>
													<Storyboard>
														<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
															<DiscreteObjectKeyFrame KeyTime="0">
																<DiscreteObjectKeyFrame.Value>
																	<System:Boolean>true</System:Boolean>
																</DiscreteObjectKeyFrame.Value>
															</DiscreteObjectKeyFrame>
														</ObjectAnimationUsingKeyFrames>
													</Storyboard>
												</BeginStoryboard>
											</EventTrigger>
										</ToolTip.Triggers>
									</ToolTip>
								</ToolTipService.ToolTip>
								<Grid Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12" Background="Transparent">
									<Path Fill="#FFDC000C" Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z"/>
									<Path Fill="#ffffff" Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8"/>
								</Grid>
							</Border>
							<Popup x:Name="Popup">
								<Grid Opacity="{TemplateBinding Opacity}">
									<Border x:Name="PopupBorder" HorizontalAlignment="Stretch" Opacity="0" Background="#11000000" BorderThickness="0">
										<Border.RenderTransform>
											<TranslateTransform X="1" Y="1"/>
										</Border.RenderTransform>
										<Border HorizontalAlignment="Stretch" Opacity="1.0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0" Padding="0">
											<Border.RenderTransform>
												<TransformGroup>
													<TranslateTransform X="-1" Y="-1"/>
												</TransformGroup>
											</Border.RenderTransform>
											<Border.Background>
												<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
													<GradientStop Color="#FFDDDDDD" Offset="0"/>
													<GradientStop Color="#AADDDDDD" Offset="1"/>
												</LinearGradientBrush>
											</Border.Background>
											<ListBox x:Name="Selector" Loaded="Selector_Loaded" Background="{TemplateBinding Background}" BorderThickness="0" Foreground="{TemplateBinding Foreground}" ItemTemplate="{TemplateBinding ItemTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemContainerStyle="{TemplateBinding ItemContainerStyle}"/>
										</Border>
									</Border>
								</Grid>
							</Popup>
						</Grid>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</UserControl.Resources>

    <Grid x:Name="LayoutRoot" Margin="10" >
        <Grid>
            <StackPanel>
                <input:AutoCompleteBox x:Name="acb1" KeyDown="Selector_KeyDown" Style="{StaticResource AutoCompleteBoxStyle1}"/>
            </StackPanel>
        </Grid>
    </Grid>
 

code 

   public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < 100; i++)
                list.Add("hello" + i);
            acb1.ItemsSource = list;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
        }

        private void Selector_KeyDown(object sender, KeyEventArgs e)
        {
            var selecter = _listbox;
            if (selecter == null)
                return;
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                switch (e.Key)
                {
                    case Key.Home:
                        selecter.SelectedIndex = 0;
                        break;
                    case Key.End:
                        selecter.SelectedIndex = selecter.Items.Count-1;
                        break;
                }
            }
         }

        ListBox _listbox;
        private void Selector_Loaded(object sender, RoutedEventArgs e)
        {
            _listbox = sender as ListBox;
        }
    }
 

Please have a try.

Thanks,

Mog Liang
Microsoft Online Community Support

Please remember to mark the replies as answers if they help and unmark them if they provide no help.

kobruleht
kobruleht

Member

Member

161 points

579 Posts

Re: AutoCompleteBox: implementing page/up down in popup

Mog,

thank you. I tried to implement page up/down based on this using code below. This works but uses hard-coded page size (30). How to find number

of visible rows in ListBox ? 

Or any other idea how to implement page up/down keys?

Andrus.

protected override void OnKeyDown(KeyEventArgs e)

{

ListBox selecter = _listbox;if (selecter == null)

{

base.OnKeyDown(e);

return;

}

switch (e.Key)

{

case Key.PageDown:if (selecter.SelectedIndex + 30 < selecter.Items.Count)

selecter.SelectedIndex += 30;

else

selecter.SelectedIndex = selecter.Items.Count-1;

e.Handled =
true;

break;

case Key.PageUp:if (selecter.SelectedIndex > 30)

selecter.SelectedIndex -= 30;

else

selecter.SelectedIndex = 0;

e.Handled =
true;

break;

}

base.OnKeyDown(e);

Mog Liang - MSFT
Mog Lian...

All-Star

All-Star

15884 points

1,541 Posts

Re: AutoCompleteBox: implementing page/up down in popup

Hi,

I suppose each item has same height, then we can get display item count by listbox.actualheight/listboxitem.acutalheight. it may be not accurate.

Here is code 

        private void Selector_KeyDown(object sender, KeyEventArgs e)
        {
            var selecter = _listbox;
            if (selecter == null)
                return;

            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                try
                {
                    // get listbox height
                    var length = _listbox.ActualHeight;
                    // get one item height
                    var itemheight = _listbox.GetContainers().FirstOrDefault().ActualHeight;
                    // calculate visible item count
                    int visiblecount = (int)(length / itemheight);
                    var curindex = _listbox.SelectedIndex;
                    switch (e.Key)
                    {
                        case Key.Home:
                            curindex -= visiblecount;
                            _listbox.SelectedIndex = Math.Max(0, curindex);
                            break;
                        case Key.End:
                            curindex += visiblecount;
                            _listbox.SelectedIndex = Math.Min(_listbox.Items.Count - 1, curindex);
                            break;
                    }
                }
                catch { }
            }
         }

 Thanks,

Mog Liang
Microsoft Online Community Support

Please remember to mark the replies as answers if they help and unmark them if they provide no help.
  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities