【问题标题】:How can I access a ListBox within a TabControl.ContentTemplate?如何访问 TabControl.ContentTemplate 中的 ListBox?
【发布时间】:2013-04-11 06:18:15
【问题描述】:

在我后面的代码中,我将 MessageBoxTabControl.ItemsSource 设置为 Observable Collection。

<TabControl x:Name="MessageBoxTabControl">
    <TabControl.ContentTemplate>
        <DataTemplate>
            <ListBox x:Name="MessageListBox" />
                <!-- ^ I want a reference to this control -->
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

假设我有相关的 tabcontrol 和 tabitem,我怎样才能获得对我的 ListBox 的引用?

【问题讨论】:

标签: wpf


【解决方案1】:

你有没有想过以其他方式做任何你想做的事?通常,当您拥有 DataTemplate 时,您可能希望在该模板内的控件上设置的任何属性都应该是静态的(所以为什么要访问它们)或取决于提供的数据,然后应该由 DataBinding 实现。

您可以使用以下代码来获取 ListBox。我仍然觉得重新考虑你的结构而不是使用这段代码会更好。

Xaml:

<Window x:Class="WpfApplication1.MainWindow"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    Title="MainWindow" Height="350" Width="525">

    <TabControl x:Name="MessageBoxTabControl">
        <TabControl.ContentTemplate>
            <DataTemplate >
                <ListBox x:Name="MessageListBox" >
                    <ListBoxItem Content="ListBoxItem 1" /> <!-- just for illustration -->
                </ListBox>
            </DataTemplate>
        </TabControl.ContentTemplate>
        <TabItem Header="Tab 1" />
        <TabItem Header="Tab 2" />
    </TabControl>
</Window>

后面的代码:

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    ListBox lbx = FindVisualChildByName<ListBox>(this.MessageBoxTabControl, "MessageListBox");
    if (lbx != null)
    {
        // ... what exactly did you want to do ;)?
    }
}

private T FindVisualChildByName<T>(DependencyObject parent, string name) where T : FrameworkElement
{
    T child = default(T);
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var ch = VisualTreeHelper.GetChild(parent, i);
        child = ch as T;
        if (child != null && child.Name == name)
            break;
        else
            child = FindVisualChildByName<T>(ch, name);

        if (child != null) break;
    }
    return child;
}

还有第二种类似的方式,实际使用模板,但仍然依赖于可视化树来获取 ContentPresenter(FindVisualChild 实现类似于上面):

ContentPresenter cp = FindVisualChild<ContentPresenter>(this.MessageBoxTabControl);
ListBox lbx = cp.ContentTemplate.FindName("MessageListBox", cp) as ListBox;

请注意,由于对可视化树的这种依赖性,使用此方法您将始终只能找到所选选项卡的 ListBox。

【讨论】:

    【解决方案2】:

    应该是这样的:

    TabItem relevantTabItem = howeverYouGetThisThing();
    var grid = System.Windows.Media.VisualTreeHelper.GetChild(relevantTabItem, 0);
    var listBox = (ListBox) System.Windows.Media.VisualTreeHelper.GetChild(grid, 0);
    

    【讨论】:

    • 实际返回一个 Grid
    • 抱歉,不知道,再深入一层
    • 也许您甚至需要进一步深入研究。毕竟,我不知道 TabControl.ContentTemplate 是如何构建的,但我想它不应该是您基本上必须使用 VisualTreeHelper 遍历的太复杂的事情。事实上,我也猜想你在这里问错了问题,而应该问你真正想用这个来完成什么,因为这很可能可以通过将 ListBox 的属性绑定到 viewModel 属性来解决,你可以然后轻松更改您的模型。
    • 我想要列表框的隐式滚动查看器。我认为没有绑定属性选项。孩子是 TabItem->Grid->Border->ContentPresenter->TextBlock
    • 谷歌搜索,我找到了这个答案:stackoverflow.com/questions/10293236/… 正在做一些相关的事情。但我想在这里复制粘贴它是没用的。 ;-) 希望这对您有所帮助,我认为它会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多