简体   繁体   中英

How to find control from datatemplate of tabitem wpf

I have TabControl:

<TabControl Name="tabControl"                   
            VerticalAlignment="Top"
            HorizontalAlignment="Stretch">
    <TabControl.Items>
        <TabItem  x:Name="tab1" Header="ABC">                       
            <TabItem.ContentTemplate>                            
                <DataTemplate>
                    <ScrollViewer Name="ScrollViewer">
                        <StackPanel Orientation="Vertical">
                            <TextBox Name="txt1" HorizontalAlignment="Center" Margin="0,26,0,0" />
                            <ListBox Name="listBox" DataContext="{Binding Items, Mode=TwoWay}"  />
                        </StackPanel>
                    </ScrollViewer>
                </DataTemplate>
            </TabItem.ContentTemplate>
        </TabItem>
    </TabControl.Items>
</TabControl>

How I can get listbox programmatically in C# code?

I have tried below code and myContentPresenter.ContentTemplate shows null.

TabItem myListBoxItem = (TabItem)(tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
ListBox listBox = (ListBox)myDataTemplate.FindName("listBox", myContentPresenter);

The ListBox is not a visual child of the TabItem but it is a visual child of the TabControl itself provided that the "ABC" tab is actually selected.

You need to wait for it to get added to the visual tree before you can access it though. This should work:

private void tabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (tabControl.SelectedItem == tab1)
    {
        tabControl.Dispatcher.BeginInvoke(new Action(() =>
        {
            ListBox lb = FindVisualChild<ListBox>(tabControl);
            MessageBox.Show(lb.Items.Count.ToString());
        }));
    }
}

Only the elements of the currently visible TabItem are added to the visual tree. When you switch tabs, the invisible elements are removed.

Building on @mm8 approach, the following solution will find the ListBox by name instead of by type:

XAML

<TabControl x:Name="tabControl1" SelectionChanged="tabControl1_SelectionChanged">
    <TabItem  x:Name="tab1" Header="ABC">
        <TabItem.ContentTemplate>
            ...

Code

private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    Dispatcher.BeginInvoke(new Action(() => TabItem_UpdateHandler()));
}


void TabItem_UpdateHandler()
{
    ContentPresenter myContentPresenter = tabControl1.Template.FindName("PART_SelectedContentHost", tabControl1) as ContentPresenter;
    if (myContentPresenter.ContentTemplate == tab1.ContentTemplate)
    {
        myContentPresenter.ApplyTemplate();
        var lb1 = myContentPresenter.ContentTemplate.FindName("listBox", myContentPresenter) as ListBox;
    }
}

You can use the following function to get the Visual Child of a WPF control:

private static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
    for (int childCount = 0; childCount < VisualTreeHelper.GetChildrenCount(parent); childCount ++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, childCount);
        if (child != null && child is T)
            return (T)child;
        else
        {
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}

Usage:

ListBox lb = MainWindow.FindVisualChild<ListBox>(tabControl);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM