如何获取ListBox的子控件?

时间:2015-02-02 22:14:59

标签: c# xaml silverlight listbox

我在xaml中有一个ListBox,它在顶级ListBox的项目模板中有一个子ListBox。因为子ListBox是多选的,并且由于某种原因我无法将子ListBox的SelectedItems绑定到viewmodel属性,所以我试图在视图代码中做很多事情 - 后面。

我有一切正常,除了一个障碍:我想默认选择每个子ListBox中的所有项目。由于SelectedItems没有数据绑定,每当SelectionChanged事件在顶级ListBox上触发时,我都会尝试在代码中手动执行此操作。问题是我不知道如何从顶级ListBox到顶级选定项的子ListBox。我想我需要使用可视树,但我不知道如何获得与所选项对应的依赖对象。

以下是代码:

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

转换器确保只有选定的顶级项目具有可见的子列表框,并且它正在工作。

我需要实现以下方法:

private void StuffListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox stuffListBox = (ListBox)sender;

    foreach (Stuff stuff in e.AddedItems)
    {
        ...
        subStuffListBox.SelectAll();
    }
}

我尝试了stuffListBox.ItemContainerGenerator.ContainerFromItem(stuff),但总是返回null。即使stuffListBox.ItemContainerGenerator.ContainerFromIndex(0)始终返回null。

我也从选择更改方法中得到奇怪的行为。 &#39; e.AddedItems将包含项目,但stuffListBox.SelectedItem始终为空。我错过了什么吗?

从我所读过的内容来看,我的问题来自于我在获得选择更改事件时尚未生成容器的事实。我已经看到了涉及收听项目容器生成器状态更改事件的变通方法,但我在Silverlight中工作并且无法访问该事件。由于忽略了将ListBox上的SelectedItems设为只读,我在Silverlight中做的事情是不可能的吗?

1 个答案:

答案 0 :(得分:2)

就像你说的那样,最好在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();
}

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