ListView -将焦点设置在新行(UWP)中的控件上

本文关键字:UWP 控件 新行 焦点 设置 ListView | 更新日期: 2023-09-27 18:13:10

我有一个由ObservableCollection支持的ListView。用户可以添加一个新行,在代码中我添加一个新对象到集合:array.Add(obj)

现在我要做的是将焦点放在新行中的TextBox上。问题是,我相信我需要等待,直到UI被创建,我不知道一个事件,会让我知道什么时候新的行准备好了。

我已经尝试在ListView_SelectionChanged中获得新的容器和对TextBox的引用,但我在新行上获得空返回值。

我试过使用ListViewItem.Loaded,但这似乎并没有被称为回收行。

我也尝试了ListViewItem.GotFocus,但在代码中添加新行后没有调用。

如果我知道ListViewItem上的控制准备好了,我就可以找到TextBox并设置它的焦点。

也许我让它比它需要的更困难,但我不确定如何继续。

ListView -将焦点设置在新行(UWP)中的控件上

我在回答自己的问题。下面是我想出来的。

Xaml:(添加两个事件处理程序到Grid)

<DataTemplate x:Key="MyTemplate" x:DataType="model:Card">
    <Grid GotFocus="ListViewGrid_GotFocus" DataContextChanged="ListViewGrid_DataContextChanged">
        <StackPanel Orientation="Horizontal">
            <TextBox Name="Text1" Text="{x:Bind Text1}" />
        </StackPanel>
    </Grid>
</DataTemplate>
代码:

MyListView.Items.VectorChanged += ListViewItems_VectorChanged; // in constructor
private void AddRow_Click(object sender, RoutedEventArgs e) {
    card = ....
    _newRowCard = card;
    _array.Add(card);
}
private void ListViewItems_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs @event) {
    // If new row added, at this point we can safely select and scroll to new item
    if (_newRowCard != null) {
        MyListView.SelectedIndex = MyListView.Items.Count - 1; // select row
        MyListView.ScrollIntoView(MyListView.Items[MyListView.Items.Count - 1]);   // scroll to bottom; this will make sure new row is visible and that DataContextChanged is called
    }
}
private void ListViewGrid_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args) {
    // If new row added, at this point the UI is created and we can set focus to text box 
    if (_newRowCard != null) {
        Grid grid = (Grid)sender;
        Card card = (Card)grid.DataContext;  // might be null
        if (card == _newRowCard) {
            TextBox textBox = FindControl<TextBox>(grid, typeof(TextBox), "Text1");
            if (textBox != null) textBox.Focus(FocusState.Programmatic);
            _newRowCard = null;
        }
    }
}
private void ListViewGrid_GotFocus(object sender, RoutedEventArgs e) {
    // If user clicks on a control in the row, select entire row
    MyListView.SelectedItem = (sender as Grid).DataContext;
}
public static T FindControl<T>(UIElement parent, Type targetType, string ControlName) where T : FrameworkElement {
    if (parent == null) return null;
    if (parent.GetType() == targetType && ((T)parent).Name == ControlName) return (T)parent;
    int count = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < count; i++) {
        UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
        T result = FindControl<T>(child, targetType, ControlName);
        if (result != null) return result;
    }
    return null;
}