2017-06-12 52 views
1

控制我的TabControl:如何找到的DataTemplate的TabItem的WPF

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

我如何在C#代码获得列表框编程?

我试过下面的代码,​​显示为空。

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

您还没有提供良好[mcve]显示要获取该对象引用的代码的上下文。并不是说堆栈溢出在处理这种基本类型的场景方面还没有很多问题;如果你花一点时间看,我相信你会找到你想要的答案。也就是说,你需要的答案是,你不应该试图在代码背后获取ListBox对象。无论你认为你想用这个对象做什么,你都应该通过一个视图模型来处理,而不是你为'TabItem'使用的模型。再次,没有上下文,没有答案。 –

+0

如果你找不到'ListBox',那么在'ListBox'的'Loaded'事件上放置一个处理器,然后在该处理器的VS中放置一个断点,当你将断点悬停在你的sender参数上时解决方案,然后你会看到可视树,然后你可以找到'ListBox'。 – XAMlMAX

+0

从哪里获得控制权? (构造函数,加载事件,其他事件,...?),并且是包含您的控件当前处于活动状态的Tab,还是在尝试查找控件时是否存在其他活动的Tab? – grek40

回答

1

大厦,以下解决方案将找到ListBox通过名称而不是类型:

XAML

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

代码

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

我使用调度程序的方法有什么问题?它为我创造奇迹。 – mm8

+0

@ mm8可能没有错。只是一个不完整的答案,因为你没有打扰到使用控件名称。但是我越想越多,我认为你对使用Dispatcher解决我提到的问题是正确的。可能是我在这里失败了,但你仍然可以在调度程序中使用FindName方法;) – grek40

+0

由于在这种情况下只有一个ListBox,所以不需要“打扰”ListBox的名称。 – mm8

1

您可以使用下面的函数来得到一个WPF控件的视觉孩子:

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

用法:

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

这一个返回null – vishal

+0

它返回'ListBox'为我 – Abhishek

2

ListBox不是TabItem的视觉孩子,但它是TabControl本身的可视孩子,前提是实际选择了“ABC”选项卡。

您需要等待它被添加到可视化树,然后才能访问它。这应该有效:

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

只将当前可见的TabItem的元素添加到可视化树中。当您切换标签时,不可见元素将被删除。在@ MM8方法

+0

关于'TabControl.Content'而不是'TabItem'的部分是有效的,但不应该仍然利用'ContentTemplate'和'FindName '就像最后两条代码行一样(只是使用不同的ContentPresenter)? – grek40

+0

否。DataTemplate只是一个模板。他需要获得对ListBox的实际实例的引用,而不管这是否是使用模板创建的。 – mm8

+0

但是,如果不考虑ElementName,只要涉及多个ListBox,就会中断。 – grek40