如何在后面的代码中获取 ListBox ItemsPanel

Posted

技术标签:

【中文标题】如何在后面的代码中获取 ListBox ItemsPanel【英文标题】:How to get ListBox ItemsPanel in code behind 【发布时间】:2011-11-11 07:22:43 【问题描述】:

我有一个带有 ItemsPanel 的 ListBox

<Setter Property="ItemsPanel">
    <Setter.Value>
        <ItemsPanelTemplate>
             <StackPanel x:Name="ThumbListStack" Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </Setter.Value>
</Setter>

我想在后面的代码中使用 TranslateTransform 沿 X 轴移动堆栈面板。

问题是,我找不到堆栈面板。

ThumbListBox.FindName("ThumbListStack")

什么都不返回。 我想用在:

Storyboard.SetTarget(x, ThumbListBox.FindName("ThumbListStack"))

我如何获得堆栈面板,以便我可以将它与 TranslateTransform 一起使用

谢谢

【问题讨论】:

如果这只是一个ListBox,您可以将Loaded 事件用于StackPanel,然后将其存储在后面的代码中 嗨,Meleak,我如何附加到 StackPanel 的 Loaded 事件?我在 VS 中看不到它是一个选项 我添加了一个关于如何使用Loaded 事件的答案,如果您的样式定义在与Listbox 相同的视图中,该事件将起作用。否则,您可以使用我的答案的第二部分搜索可视树 【参考方案1】:

抱歉,我刚刚注意到我忘记保存编辑了...我意识到您已经接受了答案,但对我来说这似乎更像是一种黑客行为。这是我对 FindChild 的实现,您可能希望将来使用它,或者如果您要经常这样做。

public static T FindChild<T>(this FrameworkElement obj, string name)

    DependencyObject dep = obj as DependencyObject;
    T ret = default(T);

    if (dep != null)
    
        int childcount = VisualTreeHelper.GetChildrenCount(dep);
        for (int i = 0; i < childcount; i++)
        
            DependencyObject childDep = VisualTreeHelper.GetChild(dep, i);
            FrameworkElement child = childDep as FrameworkElement;

            if (child.GetType() == typeof(T) && child.Name == name)
            
                ret = (T)Convert.ChangeType(child, typeof(T));
                break;
            

            ret = child.FindChild<T>(name);
            if (ret != null)
                break;
        
    
    return ret;

它检查所有子项和子项的子项,比较控件上设置的类型和名称。像这样使用它:

StackPanel ipanel = ThumbListBox.FindChild<StackPanel>("ThumbListStack");
if(ipanel == null)
    MessageBox.Show("couldn't find anything");
else
    MessageBox.Show("Aha! Found: " ipanel.Name);

【讨论】:

嗨,萨阿德,感谢您的回复。我还处于 WPF 的早期阶段,但我对 FindParent 的解释是它会上树,而不是下树。 ItemsPanel 不是在树下吗?即 StackPanel 是 ThumbListBox 的子项? 嘿本,对不起,我第一次误解了。没错,StackPanel 是 ThumbListBox 的子项。我更新了我的答案。 嗨,Saad,我看不到您的回答有任何变化? @Ben 嘿,对不起。我忘了保存我的编辑。我现在保存了它,您可能仍想使用它,或者将来可能会使用它。【参考方案2】:

尝试以下扩展方法:

var childStackPanels = FindVisualChildren<StackPanel>(ThumbListBox);

方法本身:

public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj) where T : DependencyObject

    if (depObj != null)
    
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            var typedChild = child as T;
            if (typedChild != null)
            
                yield return typedChild;
                

            foreach (T childOfChild in FindVisualChildren<T>(child))
            
                yield return childOfChild;
            
        
    

PS:您可以自己扩展它以检查特定的控件名称,因此方法将返回单个控件而不是列表。

【讨论】:

【参考方案3】:

您可以将Loaded 事件用于ItemsPanelTemplate 中的StackPanel

<Grid>
    <Grid.Resources>
        <Style TargetType="ListBox">
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel x:Name="ThumbListStack" Orientation="Horizontal"
                                    Loaded="StackPanel_Loaded" />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <ListBox />
</Grid>

然后在代码后面

private StackPanel m_itemsPanelStackPanel;
private void StackPanel_Loaded(object sender, RoutedEventArgs e)

    m_itemsPanelStackPanel = sender as StackPanel;

另一种方法是遍历可视树并找到StackPanel,这将是ItemsPresenter 的第一个孩子。

public void SomeMethod()

    ItemsPresenter itemsPresenter = GetVisualChild<ItemsPresenter>(listBox);
    StackPanel itemsPanelStackPanel = GetVisualChild<StackPanel>(itemsPresenter);


private static T GetVisualChild<T>(DependencyObject parent) where T : Visual

    T child = default(T);

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        
            child = GetVisualChild<T>(v);
        
        if (child != null)
        
            break;
        
    
    return child;

【讨论】:

最好将 GetVisualChild() 重命名为 GetFirstVisualChild() @Ben:很高兴听到它奏效了,很高兴为您提供帮助 :) 您知道,现在您的声誉得分超过 15,您可以投票赞成您认为有帮助的答案。 这也可以在Initialized 事件处理程序中完成。然后,成员变量将在初始化阶段设置并且已经有效,例如当引发父控件或窗口的 Loaded 事件时。

以上是关于如何在后面的代码中获取 ListBox ItemsPanel的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 ListBox 的对象?

c# winform listbox 如何 获取 当前 选中的值 急!!!

将 ListBox.items 转换为通用列表的最简洁方法

DELPHI如何读取cxcheckcombobox中的值,在后面的代码中要用到其中的数据(数据库有多个,一个的我会)

如何将listbox中选中的项删除?

如何在后面的代码中获取使用 Raduploader 动态创建的文本框的值?