问题
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);
回答1:
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;
}
}
回答2:
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.
回答3:
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);
来源:https://stackoverflow.com/questions/44492970/how-to-find-control-from-datatemplate-of-tabitem-wpf