1

In my code behind I set the MessageBoxTabControl.ItemsSource to an Observable Collection.

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

Assuming I have the relevant tabcontrol and tabitem, how can I get a reference to my ListBox?

patrick
  • 16,091
  • 29
  • 100
  • 164

2 Answers2

4

Have you thought about doing whatever you want to do some other way? Normally, when you have a DataTemplate, any properties you could want to set on the controls inside that template should either be static (so why access them) or depend upon the data supplied, which then should be implemented by a DataBinding.

You can use the following code to get the ListBox. I still feel it would be better to rethink your structure instead of using this code.

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>

Code behind:

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

There is also a second, similar way, that actually uses the template, but still depends on the visual tree to get to the ContentPresenter (FindVisualChild implementation analogous to above):

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

Note that because of this dependency on the visual tree, you will always only find the ListBox of the selected tab with this method.

Mike Fuchs
  • 12,081
  • 6
  • 58
  • 71
0

Should be this:

TabItem relevantTabItem = howeverYouGetThisThing();
var grid = System.Windows.Media.VisualTreeHelper.GetChild(relevantTabItem, 0);
var listBox = (ListBox) System.Windows.Media.VisualTreeHelper.GetChild(grid, 0);
Akku
  • 4,373
  • 4
  • 48
  • 67
  • That returns a Grid actually – patrick Apr 10 '13 at 19:17
  • Sorry, didn't know that, then go one level deeper – Akku Apr 10 '13 at 19:22
  • Maybe you even need to drill further down. After all, I don't know how exactly the TabControl.ContentTemplate is built, but I imagine it shouldn't be a too complex thing that you basically have to traverse with the VisualTreeHelper. In fact I also guess that you're asking the wrong question here and should rather have asked what you actually want to accomplish with this, because most likely this can be solved by Binding a property of the ListBox to a viewModel property, that you can then easily change in your model. – Akku Apr 10 '13 at 19:29
  • I want the implicit scrollviewer of the listbox. I don't think there is a binding property option for that. The children are TabItem->Grid->Border->ContentPresenter->TextBlock – patrick Apr 10 '13 at 19:35
  • Googling for this, I found this answer: http://stackoverflow.com/questions/10293236/accessing-the-scrollviewer-of-a-listbox-from-c-sharp which is doing something related. But I guess copypasting it here would be useless. ;-) Hope this helps you, I think it will work. – Akku Apr 10 '13 at 19:41