Dav*_*itt 14 wpf listview internals
在一个事件中,我想把重点放在ListViewItem模板中的特定TextBox上.XAML看起来像这样:
<ListView x:Name="myList" ItemsSource="{Binding SomeList}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- Focus this! -->
<TextBox x:Name="myBox"/>
Run Code Online (Sandbox Code Playgroud)
我在后面的代码中尝试了以下内容:
(myList.FindName("myBox") as TextBox).Focus();
Run Code Online (Sandbox Code Playgroud)
但我似乎误解了FindName()文档,因为它返回了null.
也ListView.Items没有帮助,因为(当然)包含我绑定的业务对象而没有ListViewItems.
也没有myList.ItemContainerGenerator.ContainerFromItem(item),也返回null.
Dav*_*itt 18
要理解为什么ContainerFromItem不适合我,这里有一些背景知识.我需要此功能的事件处理程序如下所示:
var item = new SomeListItem();
SomeList.Add(item);
ListViewItem = SomeList.ItemContainerGenerator.ContainerFromItem(item); // returns null
Run Code Online (Sandbox Code Playgroud)
后Add()在ItemContainerGenerator不立即创建容器,因为CollectionChanged事件可能在非UI线程处理.相反,它启动异步调用并等待UI线程回调并执行实际的ListViewItem控件生成.
要在发生这种情况时收到通知,将ItemContainerGenerator公开StatusChanged在生成所有Container之后触发的事件.
现在我必须听这个事件并决定控件当前是否想要设置焦点.
Abe*_*cht 14
正如其他人所说,通过在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<bool>(tb.Focus));
}
}
private FrameworkElement FindByName(string name, FrameworkElement root)
{
Stack<FrameworkElement> tree = new Stack<FrameworkElement>();
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;
}
Run Code Online (Sandbox Code Playgroud)
我注意到问题标题与问题内容没有直接关系,接受的答案也没有回答它。我已经能够通过使用以下方法“访问 WPF ListView 的 ListViewItems”:
public static IEnumerable<ListViewItem> GetListViewItemsFromList(ListView lv)
{
return FindChildrenOfType<ListViewItem>(lv);
}
public static IEnumerable<T> FindChildrenOfType<T>(this DependencyObject ob)
where T : class
{
foreach (var child in GetChildren(ob))
{
T castedChild = child as T;
if (castedChild != null)
{
yield return castedChild;
}
else
{
foreach (var internalChild in FindChildrenOfType<T>(child))
{
yield return internalChild;
}
}
}
}
public static IEnumerable<DependencyObject> GetChildren(this DependencyObject ob)
{
int childCount = VisualTreeHelper.GetChildrenCount(ob);
for (int i = 0; i < childCount; i++)
{
yield return VisualTreeHelper.GetChild(ob, i);
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定递归有多忙,但在我的情况下它似乎工作得很好。不,我yield return以前没有在递归上下文中使用过。
| 归档时间: |
|
| 查看次数: |
37746 次 |
| 最近记录: |