5

I'm writing a Universal Windows App and I have a ListView where the ListViewItems contain a TextBox and a Button. When I click in the text box I would like that ListViewItem to become selected. I've found solutions for WPF but Style.Triggers isn't available in UWP. Can anyone point me to the correct way to do this?

<Page 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:controls="using:CycleStreetsUniversal.Controls" xmlns:common="using:CycleStreetsUniversal.Common" xmlns:utils="using:CycleStreetsUniversal.Utils" xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:core="using:Microsoft.Xaml.Interactions.Core" xmlns:converters="using:CycleStreetsUniversal.Converters" x:Class="CycleStreetsUniversal.Pages.HomePage" mc:Ignorable="d" FontWeight="Light"> <Page.Resources> <DataTemplate x:Key="DirectionItem"> <Grid Padding="8,6,0,6"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="50"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <AutoSuggestBox x:Name="autoSuggestBox" PlaceholderText="{Binding Watermark}" QueryIcon="Find" Text="{Binding LocationName}" /> <Button Grid.Column="2" Visibility="{Binding ShowAddButton, Converter={StaticResource BooleanToVisibilityConverter}}" /> <Button Grid.Column="1" Visibility="{Binding ShowMinusButton, Converter={StaticResource BooleanToVisibilityConverter}}" /> </Grid> </DataTemplate> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid x:Name="Directions" HorizontalAlignment="Left" Margin="0" Width="346" DataContext="{Binding DirectionPlanner, Mode=OneWay, Source={StaticResource Locator}}"> <Grid.Background> <SolidColorBrush Color="{ThemeResource SystemAltHighColor}"/> </Grid.Background> <StackPanel VerticalAlignment="Top"> <ListView x:Name="DirectionEntryList" ItemTemplate="{StaticResource DirectionItem}" ItemsSource="{Binding Entries}"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> </Style> </ListView.ItemContainerStyle> </ListView> <Button x:Name="crosshairButton" VerticalAlignment="Top" d:LayoutOverrides="LeftPosition, RightPosition" Margin="20,0" HorizontalAlignment="Stretch" Padding="0" Click="crosshairButton_Click"> <Grid Height="50"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Image x:Name="image" Source="ms-appx:///Assets/crosshair.png"/> <TextBlock Text="Set Location to Crosshair" Grid.Column="1" VerticalAlignment="Center" MaxLines="2" TextWrapping="Wrap"/> </Grid> </Button> </StackPanel> </Grid> </Grid> </Page> 

The AutoSuggestBox in the data template needs to set the selected item in DirectionEntryList to the List View item that the AutoSuggestBox is a child of.

3
  • You want to do it with or without code-behind? Commented Oct 13, 2015 at 8:47
  • Ideally something reusable on multiple elements - not just the AutoCompleteBox Commented Oct 13, 2015 at 12:41
  • I would add a IsSelected property to the class of the item and bind to that and change that as I gain focus or other events of the datatemplate Commented Oct 13, 2015 at 13:56

2 Answers 2

9
+50

Code behind solution

What you can do is to subscribe to the AutoSuggestBox's GotFocus event.

<AutoSuggestBox x:Name="autoSuggestBox" GotFocus="autoSuggestBox_GotFocus" /> 

Then, you just need to use the ListView.ContainerFromItem method to locate the actual ListViewItem and set its IsSelected property to true.

private void autoSuggestBox_GotFocus(object sender, RoutedEventArgs e) { var item = ((AutoSuggestBox)sender).DataContext; var container = (ListViewItem)DirectionEntryList.ContainerFromItem(item); container.IsSelected = true; } 

Blend friendly solution (no code behind)

Let's improve this answer a bit by encapsulating the logic into a Behavior.

First, you need to add Behaviors SDK(XAML) (version 12.0 atm) from the Reference Manager > Universal Windows > Extensions.

Then basically you just need to create a dependency property to obtain a reference of the DirectionEntryList and handle the GotFocus event exactly the same way as in the code behind.

public class SelectListViewItemWhenElementGotFocusBehavior : DependencyObject, IBehavior { private UIElement _element; public DependencyObject AssociatedObject { get; set; } #region ListView reference public ListView ListView { get { return (ListView)GetValue(ListViewProperty); } set { SetValue(ListViewProperty, value); } } public static readonly DependencyProperty ListViewProperty = DependencyProperty.Register("ListView", typeof(ListView), typeof(SelectListViewItemWhenElementGotFocusBehavior), new PropertyMetadata(null)); #endregion public void Attach(DependencyObject associatedObject) { AssociatedObject = associatedObject; _element = this.AssociatedObject as UIElement; if (_element != null) { _element.GotFocus += OnElementGotFocus; } } private void OnElementGotFocus(object sender, RoutedEventArgs e) { var item = ((AutoSuggestBox)sender).DataContext; var container = (ListViewItem)ListView.ContainerFromItem(item); container.IsSelected = true; } public void Detach() { if (_element != null) { _element.GotFocus -= OnElementGotFocus; } } } 

To use it, just open Blend, go to the DataTemplate and attach it to your AutoSuggestBox.

<AutoSuggestBox x:Name="autoSuggestBox"> <Interactivity:Interaction.Behaviors> <local:SelectListViewItemWhenElementGotFocusBehavior ListView="{Binding ElementName=DirectionEntryList}" /> </Interactivity:Interaction.Behaviors> </AutoSuggestBox> 
Sign up to request clarification or add additional context in comments.

4 Comments

Loving your work. Used the blend solution. Works like a charm :)
@JustinXL Hi, great solution (BLEND), but in my case i have a button, it works "FINE" except because private void OnElementGotFocus(object sender, RoutedEventArgs e) runs many times with only one click, maybe I think, because Listview GotFocus call Button GotFocus creating a loop. How can I do to fix it ?
Thanks! I had a button in our ListViewItem, but using Clicked worked.
I think in the detach method it should be -= instead of += for the GotFocus event?
0

When I click in the text box I would like that ListViewItem to become selected. I've found solutions for WPF but Style.Triggers isn't available in UWP.

In UWP, you can set the styles by using the ViewState.Setters and trigger the state change through GotFocus & LostFocus events.

For example:

<Page x:Class="UWPApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid x:Name="container" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ValueStates"> <VisualState x:Name="Selected"> <VisualState.Setters> <Setter Target="button.Background" Value="Red"></Setter> </VisualState.Setters> </VisualState> <VisualState x:Name="UnSelected"> <VisualState.Setters> <Setter Target="button.Background" Value="Blue"></Setter> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel> <TextBox x:Name="inputbox" GotFocus="inputbox_GotFocus" LostFocus="inputbox_LostFocus"></TextBox> <Button x:Name="button">Click Me</Button> </StackPanel> </Grid> </Page> 

C# Code:

private void inputbox_GotFocus(object sender, Windows.UI.Xaml.RoutedEventArgs e) { VisualStateManager.GoToState(this, "Selected", false); } private void inputbox_LostFocus(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this, "UnSelected", false); } 

1 Comment

I've added a cut down version of my layout code to show my setup. The AutoSuggestBox in the data template needs to set the selected item in DirectionEntryList to the List View item that the AutoSuggestBox is a child of. I'm not sure how to use the code you've suggested to solve this problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.