У меня есть DataGrid (https://github.com/CommunityToolkit/WindowsCommunityToolkit) с TemplateColumn и TextBox. К сожалению, мой TabIndex игнорируется, поэтому перейти ко второму TextBox через Tab невозможно.
Свойство TabIndex установлено правильно и имеет значения 1 и 2 соответственно.
<controls:DataGrid ItemsSource = "{x:Bind ViewModel.LocalizedTexts}" AutoGenerateColumns = "False">
<controls:DataGrid.Columns>
<controls:DataGridTextColumn Header = "locale" Binding = "{Binding Locale}" IsReadOnly = "True"/>
<controls:DataGridTextColumn Header = "current value" Binding = "{Binding OldText}" IsReadOnly = "True"/>
<controls:DataGridTemplateColumn Header = "new value">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text = "{Binding Path=Text, Mode=TwoWay}" IsTabStop = "True" TabIndex = "{Binding TabIndex}"/>
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
</controls:DataGrid.Columns>
</controls:DataGrid>
Спасибо за подсказку, забыл. Я использую WindowsCommunityToolkit.DataGrid.





Содержимое Datagridcell — это элемент управления ContentPresenter. Ваши текстовые поля на самом деле находятся в двух разных элементах управления ContentPresenter. Таким образом, вы не сможете перейти к другой ячейке через Tab. Вы можете протестировать в простом ListView, поместить несколько текстовых полей в шаблон и установить свойство TabIndex. Когда вы нажимаете клавишу TAB, вы можете обнаружить, что только текстовые поля внутри одного и того же элемента будут сфокусированы.
Спасибо за вашу помощь, но я зависим от DataGrid, потому что «SharedSizeGroup является эксклюзивным для WPF и не существует в UWP/Winui» (stackoverflow.com/q/35255276/6229375).
Что-то еще вроде DataGrid в настоящее время для меня не может быть и речи. Не смог реализовать свой проект с простым ListView.
Теперь я создал обходной путь, в котором у меня есть полный контроль над всеми UIElement, которые вообще должны быть сфокусированы.
Кроме того, курсор устанавливается соответственно для TextBoxes, если там уже есть текст.
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);
}
Расширения объекта зависимостей
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;
}
}
Нет встроенного UWP XAML или WinUI DataGrid, поэтому вам следует уточнить, какую библиотеку вы используете.