在一个事件中,我想把重点放在ListViewItem模板中的特定TextBox上.XAML看起来像这样:
我在后面的代码中尝试了以下内容:
(myList.FindName("myBox") as TextBox).Focus();
但我似乎误解了FindName()
文档,因为它返回了null
.
也ListView.Items
没有帮助,因为(当然)包含我绑定的业务对象而没有ListViewItems.
也没有myList.ItemContainerGenerator.ContainerFromItem(item)
,也返回null.
要理解为什么ContainerFromItem
不适合我,这里有一些背景知识.我需要此功能的事件处理程序如下所示:
var item = new SomeListItem(); SomeList.Add(item); ListViewItem = SomeList.ItemContainerGenerator.ContainerFromItem(item); // returns null
后Add()
在ItemContainerGenerator
不立即创建容器,因为CollectionChanged
事件可能在非UI线程处理.相反,它启动异步调用并等待UI线程回调并执行实际的ListViewItem控件生成.
要在发生这种情况时收到通知,将ItemContainerGenerator
公开StatusChanged
在生成所有Container之后触发的事件.
现在我必须听这个事件并决定控件当前是否想要设置焦点.
正如其他人所说,通过在ListView上调用FindName无法找到myBox TextBox.但是,您可以获取当前选定的ListViewItem,并使用VisualTreeHelper类从ListViewItem获取TextBox.这样做看起来像这样:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (myList.SelectedItem != null) { object o = myList.SelectedItem; ListViewItem lvi = (ListViewItem)myList.ItemContainerGenerator.ContainerFromItem(o); TextBox tb = FindByName("myBox", lvi) as TextBox; if (tb != null) tb.Dispatcher.BeginInvoke(new Func(tb.Focus)); } } private FrameworkElement FindByName(string name, FrameworkElement root) { Stack tree = new Stack (); tree.Push(root); while (tree.Count > 0) { FrameworkElement current = tree.Pop(); if (current.Name == name) return current; int count = VisualTreeHelper.GetChildrenCount(current); for (int i = 0; i < count; ++i) { DependencyObject child = VisualTreeHelper.GetChild(current, i); if (child is FrameworkElement) tree.Push((FrameworkElement)child); } } return null; }