[英]How do I get the child controls of a ListBox?
I have a ListBox in xaml which has a sub-ListBox inside the top-level ListBox's item template. 我在xaml中有一个ListBox,它在顶级ListBox的项模板中有一个子ListBox。 Because the sub-ListBox is multi-select, and I can't bind the SelectedItems of the sub-ListBox to a viewmodel property for some reason, I'm trying to do a lot of this in the view code-behind. 因为子ListBox是多选的,并且由于某种原因我无法将子ListBox的SelectedItems绑定到viewmodel属性,所以我试图在视图代码隐藏中执行大量此操作。
I have everything working, except for one snag: I want to select all items in each sub-ListBox by default. 我有一切工作,除了一个障碍:我想默认选择每个子ListBox中的所有项目。 Since the SelectedItems aren't data-bound, I'm trying to do it manually in code whenever a SelectionChanged event fires on the top-level ListBox. 由于SelectedItems不是数据绑定的,所以每当SelectionChanged事件在顶级ListBox上触发时,我都会尝试在代码中手动执行。 The problem is that I don't know how to get from the top-level ListBox to the sub-ListBox of the top-level selected item. 问题是我不知道如何从顶级ListBox到顶级选定项的子ListBox。 I think I need to use the visual tree, but I don't know how to even get the dependency object that corresponds to the selected item. 我想我需要使用可视化树,但我不知道如何获得与所选项对应的依赖项对象。
Here's the code: 这是代码:
<ListBox ItemsSource="{Binding Path=Stuff}" SelectionChanged="StuffListBox_SelectionChanged" SelectedItem="{Binding Path=SelectedStuff, Mode=TwoWay}" telerik:RadDockPanel.Dock="Bottom">
<ListBox.ItemTemplate>
<DataTemplate>
<telerik:RadDockPanel>
<TextBlock Text="{Binding Path=Name}" telerik:RadDockPanel.Dock="Top" />
<ListBox ItemsSource="{Binding Path=SubStuff}" SelectionMode="Multiple" SelectionChanged="SubStuffListBox_SelectionChanged" Visibility="{Binding Converter={StaticResource StuffToSubStuffVisibilityConverter}}" telerik:RadDockPanel.Dock="Bottom">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</telerik:RadDockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The converter ensures that only the selected top-level item has a visible sub-ListBox, and that's working. 转换器确保只有选定的顶级项具有可见的子ListBox,并且这是有效的。
I need to implement the following method: 我需要实现以下方法:
private void StuffListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox stuffListBox = (ListBox)sender;
foreach (Stuff stuff in e.AddedItems)
{
...
subStuffListBox.SelectAll();
}
}
I tried doing stuffListBox.ItemContainerGenerator.ContainerFromItem(stuff)
, but that always returns null. 我尝试做stuffListBox.ItemContainerGenerator.ContainerFromItem(stuff)
,但总是返回null。 Even stuffListBox.ItemContainerGenerator.ContainerFromIndex(0)
always returns null. 即使stuffListBox.ItemContainerGenerator.ContainerFromIndex(0)
始终返回null。
I also get strange behaviour from the selection changed method. 我也从选择改变的方法得到奇怪的行为。 ' e.AddedItems
will contain items, but stuffListBox.SelectedItem
is always null. ' e.AddedItems
将包含项,但stuffListBox.SelectedItem
始终为null。 Am I missing something? 我错过了什么吗?
From what I've read, my problem is coming from the fact that the containers haven't been generated at the time that I'm getting a selection change event. 从我读过的内容来看,我的问题来自于在我收到选择更改事件时尚未生成容器这一事实。 I've seen workarounds that involve listening for a the item container generator's status changed event, but I'm working in Silverlight and don't have access to that event. 我见过涉及监听项容器生成器状态更改事件的变通方法,但我在Silverlight中工作并且无法访问该事件。 Is what I'm doing just not possible in Silverlight due to the oversight of making SelectedItems on a ListBox read-only? 由于忽略了将ListBox上的SelectedItems设为只读,我在Silverlight中所做的事情是不可能的吗?
Like you say this is probably best done in the ViewModel but you can select all the sub list items in code behind using VisualTreeHelper. 就像你说的那样,最好在ViewModel中完成,但你可以使用VisualTreeHelper选择代码中的所有子列表项。
private void StuffListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var stuffListBox = (ListBox)sender;
ListBoxItem item = (ListBoxItem)stuffListBox.ContainerFromItem(stuffListBox.SelectedItem);
ListBox sublist = FindVisualChild<ListBox>(item);
sublist.SelectAll();
}
FindVisualChild Method as per MSDN 根据MSDN的 FindVisualChild方法
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.