Search code examples
c#wpfxamlfocusfocusmanager

cycle focus issue -


I'm rewrite default template of ListBoxItems & ListBox. Here MainWindow.xaml

<Window x:Class="NestedBindingTry.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Loaded="Window_Loaded"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <Style TargetType="ListBox">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBox">
                                <StackPanel 
                                            IsItemsHost="True"
                                            FocusManager.IsFocusScope="False"
                                            />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <StackPanel FocusManager.IsFocusScope="True"
                KeyboardNavigation.ControlTabNavigation="Cycle"
                KeyboardNavigation.DirectionalNavigation="Cycle">
        <StackPanel>
            <CheckBox Content="SelectAll" />
        </StackPanel>
        <ListBox SelectionMode="Multiple" Name="M" ItemsSource="{Binding}" FocusManager.IsFocusScope="False">
            <ListBox.Resources>
                <Style TargetType="ListBoxItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListBoxItem">
                                <Grid>
                                    <VisualStateManager.VisualStateGroups>                                        
                                        <VisualStateGroup x:Name="SelectionStates">
                                            <VisualState x:Name="Unselected">
                                                <Storyboard>
                                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetName="CheckBox"
                                                                                    Storyboard.TargetProperty="IsChecked">
                                                        <DiscreteBooleanKeyFrame KeyTime="0"
                                                                                 Value="False" />
                                                    </BooleanAnimationUsingKeyFrames>
                                                </Storyboard>
                                            </VisualState>
                                            <VisualState x:Name="Selected">
                                                <Storyboard>
                                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetName="CheckBox"
                                                                                    Storyboard.TargetProperty="IsChecked">                                                    
                                                        <DiscreteBooleanKeyFrame KeyTime="0"
                                                                                 Value="True" />
                                                    </BooleanAnimationUsingKeyFrames>
                                                </Storyboard>
                                            </VisualState>
                                            <VisualState x:Name="SelectedUnfocused">
                                                <Storyboard>
                                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetName="CheckBox"
                                                                                    Storyboard.TargetProperty="IsChecked">
                                                        <DiscreteBooleanKeyFrame KeyTime="0"
                                                                                 Value="True" />
                                                    </BooleanAnimationUsingKeyFrames>
                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>
                                    <CheckBox Focusable="False"
                                              Name="CheckBox"
                                              Content="{Binding}"
                                              Checked="CheckBox_Checked"
                                              Unchecked="CheckBox_Unchecked"
                                              VerticalAlignment="Center" 
                                              Margin="0,0,3,0" />
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.Resources>
        </ListBox>
    </StackPanel>
</Grid>
</Window>

Here codeBehind MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace NestedBindingTry
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new List<string>() { "123", "546", "789"};
    }

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        CheckBox bik = sender as CheckBox;
        DependencyObject dob = bik as DependencyObject;
        while (dob.GetType() != typeof(ListBox))
        {
            dob = VisualTreeHelper.GetParent(dob);
        }
        ListBox my = dob as ListBox;
        if (!my.SelectedItems.Contains(bik.DataContext))
            my.SelectedItems.Add(bik.DataContext);
    }

    private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
    {
        CheckBox bik = sender as CheckBox;
        DependencyObject dob = bik as DependencyObject;
        while (dob.GetType() != typeof(ListBox))
        {
            dob = VisualTreeHelper.GetParent(dob);
        }
        ListBox my = dob as ListBox;
        if (my.SelectedItems.Contains(bik.DataContext))
            my.SelectedItems.Remove(bik.DataContext);
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        this.M.SelectedItems.Add(((IList<string>)this.DataContext)[0]);
        this.M.SelectedItems.Add(((IList<string>)this.DataContext)[2]);
    }
}
}

Main idea I want to achive - is to create checkable ListBox. One feature I want to have - is Select All CheckBox. But here the problem. SelectAll CheckBox is not laying inside ListBox. So its under it.

I want that focus worked like SelectAll CheckBox lay inside ListBox. It means, that when I click Tab key, focus should go to the next CheckBox. In my case, if ListBox have more than 1 item, its just change focus between two CheckBoxes - between SelectAll CheckBox and first from ListBox item. But I want it goes down to the next ListBox item. I try to play with FocusManager's properties, but nothing happens. Any suggestion...?

Bad focus example


Solution

  • Use ItemsControl instead of ListBox.... the ListBox hails from Selector base class and this class somehow overrides simple Tab based focus for its items with Control + Up / Down Arrow in its ItemsPanel.

    When I used ItemsControl it worked.