How to know which item is focused in the Universal Windows application in Windows 10

advertisements

I have a xaml page in universal windows application in windows 10. This page contains two listboxes. Both listboxes have the same ItemsSource like

public class CategoryModel
{
 public int CategoryId {get; set;}
 public string CategoryName {get; set;}
 public List<string> ImageURL {get; set;}
}

The top listbox creates Menu header at the top in Horizontal manner and the bottom listbox creates Menu data at the bottom of the menu header in Vertical manner.

The problem is that how to know which menu data element at the bottom is in focus, so that I can highlight the same element in Menu header?

                    <ListView x:Name="lvMenuBar" Grid.Column="1" FlowDirection="LeftToRight" ItemsSource="{Binding MenuCategories}" Width="Auto">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <Button Click="MenuBarClick" HorizontalAlignment="Center" VerticalAlignment="Top" Tag="{Binding CategoryId}" Content="{Binding CategoryName}" Style="{StaticResource CustomButtonStyle}" FontFamily="Segoe UI" FontWeight="SemiBold" FontSize="18" Margin="0" Padding="20" BorderBrush="Red" BorderThickness="0" Opacity="0.5" Foreground="Black"/>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                        <ListView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <VirtualizingStackPanel Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>
                    </ListView>

                    <ListView x:Name="lvMenuBar" Grid.Column="1" FlowDirection="LeftToRight" ItemsSource="{Binding MenuCategories}" Width="Auto">
                        <ListView.ItemTemplate>
                            <DataTemplate>

The above is my XAML


If I understand the question correctly, you want to select (or otherwise highlight) an item in the top list whenever that item is selected in the bottom list. You can do this with data binding, e.g.:

<ListView
    Grid.Row="0"
    ItemsSource="{Binding MenuCategories}"
    Margin="8"
    SelectedIndex="{Binding SelectedIndex, ElementName=verticalList, Mode=OneWay}"
    >

Here the SelectedIndex property of the top list mirrors that of the bottom list.

In context, something like this:

<Page.Resources>
    <Style x:Key="CustomButtonStyle" TargetType="Button" />
</Page.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <ListView
        Grid.Row="0"
        ItemsSource="{Binding MenuCategories}"
        Margin="8"
        SelectedIndex="{Binding SelectedIndex, ElementName=verticalList, Mode=OneWay}"
        >
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:CategoryModel">
                <Button
                    HorizontalAlignment="Center"
                    VerticalAlignment="Top"
                    Tag="{Binding CategoryId}"
                    Content="{Binding CategoryName}"
                    Style="{StaticResource CustomButtonStyle}"
                    FontFamily="Segoe UI"
                    FontWeight="SemiBold"
                    FontSize="18"
                    Margin="0"
                    Padding="20"
                    BorderBrush="Red"
                    BorderThickness="0"
                    Opacity="0.5"
                    Foreground="Black"/>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
    <ListView
        x:Name="verticalList"
        Grid.Row="1"
        ItemsSource="{Binding MenuCategories}"
        Margin="8"
        IsItemClickEnabled="True"
        SelectionMode="Single">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:CategoryModel">
                <Button
                    HorizontalAlignment="Center"
                    VerticalAlignment="Top"
                    Tag="{Binding CategoryId}"
                    Content="{Binding CategoryName}"
                    Style="{StaticResource CustomButtonStyle}"
                    FontFamily="Segoe UI"
                    FontWeight="SemiBold"
                    FontSize="18"
                    Margin="0"
                    Padding="20"
                    BorderBrush="Red"
                    BorderThickness="0"
                    Opacity="0.5"
                    Foreground="Black"/>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</Grid>

Caveat: When you click one of your buttons, the ListView doesn't see that click; if you want that click to select an item, do it in code-behind.

Note also the IsItemClickEnabled property on the second (vertical) list.


EDIT: If I understand you correctly, you want the selection in the upper horizontal list to track scrolling in the lower vertical instead of selection. In that case you need to get hold of the built-in ScrollViewer and do something like this:

public MainPage()
{
    InitializeComponent();
    DataContext = this;
    Loaded += (sender, args) =>
        {
            ScrollViewer scrollViewer = FindVisualChild<ScrollViewer>(verticalList);
            if (scrollViewer != null)
            {
                scrollViewer.ViewChanged += (o, eventArgs) =>
                    {
                        int length = MenuCategories.Length;
                        double offset = scrollViewer.VerticalOffset;
                        double height = scrollViewer.ExtentHeight;
                        int index = (int)(length * offset / height);
                        horizontalList.SelectedIndex = index;
                    };
            }
        };
}

private static T FindVisualChild<T>(DependencyObject parent)
    where T : DependencyObject
{
    if (parent != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, i);
            T candidate = child as T;
            if (candidate != null)
            {
                return candidate;
            }

            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null)
            {
                return childOfChild;
            }
        }
    }

    return default(T);
}

You'll probably need to experiment with the calculations here; this is a bit experimental on my part.