Home > Net >  WindowsCommunityToolkit.DataGrid TabIndex is ignored in DataGridTemplateColumn.TextBox
WindowsCommunityToolkit.DataGrid TabIndex is ignored in DataGridTemplateColumn.TextBox

Time:05-06

I have a DataGrid (enter image description here

CodePudding user response:

The Datagridcell's content is a ContentPresenter control. Your TextBoxes are actually in two different ContentPresenter controls. So you won't be able to navigate to another cell via Tab. You could test in a simple ListView, put multiple TextBoxes inside a template, and set the TabIndex property. When you press the TAB key, you could find that only the TextBoxes inside the same item will be focused.

CodePudding user response:

Something else like the DataGrid is currently out of the question for me. Could not implement my project with a simple ListView.

I have now created a workaround where I have full control over all UIElement that are to be focused at all.

In addition, the cursor is set accordingly for the TextBoxes, should there already be text.

private void DataGrid_OnLoaded(object sender, RoutedEventArgs e)
{
    // get parent ContentDialog
    var dialog = this.FindVisualParent<ContentDialog>();

    // get all children and sort them
    // https://github.com/microsoft/microsoft-ui-xaml/blob/548cc630f37eac2658332a5f808160b2cf9f8cef/dev/ContentDialog/ContentDialog_themeresources.xaml#L311
    var uiElements = new List<UIElement>();
    dialog.FindVisualChildren(uiElements);
    var sorted = uiElements.OfType<TextBox>().Where(box => box.TabIndex > 0).Cast<UIElement>().Concat(uiElements.OfType<Button>().Where(button => button.Name.Equals("PrimaryButton") || button.Name.Equals("SecondaryButton") || button.Name.Equals("CloseButton"))).ToList();

    // catch tab keyboard event
    dialog.PreviewKeyDown  = (o, args) =>
    {
        if (args.Key == VirtualKey.Tab)
        {
            var currentFocus = sorted.FirstOrDefault(element => element.FocusState != FocusState.Unfocused);
            if (currentFocus != null)
            {
                var nextOf = currentFocus;
                n:
                var next = sorted.NextOrFirstOf(nextOf);
                if (Focus(next) == false) // can happen if a button is not visible
                {
                    nextOf = next;
                    goto n;
                }
            }
            else
            {
                Focus(sorted.First());
            }
            args.Handled = true;
        }
    };

    // focus the first empty TextBox if present
    DispatcherQueue.TryEnqueue(() =>
    {
        var textBox = sorted.OfType<TextBox>().OrderBy(box => box.Text).First();
        Focus(textBox);
    });
}

private bool Focus(UIElement element)
{
    if (element is TextBox textBox)
        textBox.SelectionStart = textBox.Text.Length;
    return element.Focus(FocusState.Programmatic);
}

DependencyObjectExtensions

public static class DependencyObjectExtensions
{
    /// <summary>
    /// Find all children by using the <see cref="VisualTreeHelper"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="startNode"></param>
    /// <param name="results"></param>
    public static void FindVisualChildren<T>(this DependencyObject startNode, List<T> results)
        where T : DependencyObject
    {
        int count = VisualTreeHelper.GetChildrenCount(startNode);
        for (int i = 0; i < count; i  )
        {
            var current = VisualTreeHelper.GetChild(startNode, i);
            if (current.GetType() == typeof(T) || current.GetType().GetTypeInfo().IsSubclassOf(typeof(T)))
            {
                var asType = (T)current;
                results.Add(asType);
            }

            current.FindVisualChildren(results);
        }
    }

    /// <summary>
    /// Find the parent <see cref="DependencyObject"/> by using the <see cref="VisualTreeHelper"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="startNode"></param>
    /// <returns></returns>
    public static T FindVisualParent<T>(this DependencyObject startNode) where T : DependencyObject
    {
        var parent = VisualTreeHelper.GetParent(startNode);
        if (parent != null)
        {
            if (parent.GetType() == typeof(T) || parent.GetType().GetTypeInfo().IsSubclassOf(typeof(T)))
            {
                return (T)parent;
            }
            else
            {
                return parent.FindVisualParent<T>();
            }
        }
        return null;
    }
}

enter image description here

  • Related