ListView - Set focus on a control in a new row (UWP)

橙三吉。 提交于 2019-12-12 04:25:58

问题


I have a ListView backed by an ObservableCollection. The user can add a new row, where in code I add a new object to the collection: array.Add(obj).

Now what I'd like to do is give focus to a TextBox in the new row. The problem is that I believe I need to wait until the UI is created, and I don't know of an event that will let me know when the new row is ready.

I've tried getting the new container and a reference to TextBox in ListView_SelectionChanged, but I was getting null return values on the new row.

I've tried using ListViewItem.Loaded, but this doesn't seem to be called for recycled rows.

I also tried ListViewItem.GotFocus, but this wasn't called after adding a new row in code.

If I knew when the controls on the ListViewItem were ready, I could then find the TextBox and set its focus.

Maybe I'm making this harder than it needs to be, but I'm not sure how to proceed.


回答1:


I'm answering my own question. Below is what I came up with.

Xaml: (add two event handlers to 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>

Code:

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;
}


来源:https://stackoverflow.com/questions/40047123/listview-set-focus-on-a-control-in-a-new-row-uwp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!