2017-06-12 90 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