2012-04-30 4 views
2

Tag 속성이 특정 값으로 설정된 특정 TreeViewItem을 찾으려고합니다. 부모 TreeViewItem이 확장 된 경우 아래 FindNode은 첫 번째 수준 항목 또는 다른 수준에서만 작동합니다. 아래 예제에서 "FFF"가 확장되면 FindNode이 예상대로 작동합니다. 항목이 작성되지 않았으므로 ContainerFromItem이 널 (null)을 리턴한다고 가정합니다. 모든 TreeViewItems의 생성을 강제하는 방법이 있습니까? 올바른 FindNode 구현이 hbarck의 답변에 따라 Tag 속성에서 특정 값을 가진 TreeViewItem을 찾으려면 어떻게합니까?


public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     this.Loaded += new RoutedEventHandler(MainWindow_Loaded);  
    } 

    private void MainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     TreeViewItem a = FindNode(__items.ItemContainerGenerator, __items.Items, Node.H); 
    } 

    private TreeViewItem FindNode(ItemContainerGenerator gen, ItemCollection items, Node value) 
    { 
     TreeViewItem oResult = null; 

     foreach (var oItem in items) 
     { 
      TreeViewItem oTreeViewItem = (TreeViewItem)gen.ContainerFromItem(oItem); 

      if (oTreeViewItem == null) { continue; } 

      if ((Node)oTreeViewItem.Tag == value) { oResult = oTreeViewItem; break; } 

      if (oTreeViewItem.Items.Count > 0) 
      { 
       oResult = FindNode(oTreeViewItem.ItemContainerGenerator, oTreeViewItem.Items, value); 

       if (oResult != null) { break; } 
      } 
     } 
     return oResult; 
    } 

} 

public enum Node { A, B, C, D, E, F, G, H, I, J, } 

<TreeView x:Name="__items"> 

     <TreeViewItem Header="AAA" 
         Tag="{x:Static my:Node.A}" /> 

     <TreeViewItem Header="BBB" 
         Tag="{x:Static my:Node.B}"> 

      <!-- Items will be added later. --> 

     </TreeViewItem> 

     <TreeViewItem Header="CCC" 
         Tag="{x:Static my:Node.C}" /> 

     <TreeViewItem Header="DDD" 
         Tag="{x:Static my:Node.D}" /> 

     <TreeViewItem Header="EEE" 
         Tag="{x:Static my:Node.E}" /> 

     <TreeViewItem Header="FFF" 
         Tag="{x:Static my:Node.F}"> 

      <TreeViewItem Header="GGG" 
          Tag="{x:Static my:Node.G}" /> 

      <TreeViewItem Header="HHH" 
          Tag="{x:Static my:Node.H}" /> 

     </TreeViewItem> 

     <TreeViewItem Header="III" 
         Tag="{x:Static my:Node.I}" /> 

    </TreeView> 
:

private TreeViewItem FindNode(ItemCollection items, Node value) 
    { 
     TreeViewItem oResult = null; 

     foreach (var oItem in items) 
     { 
      TreeViewItem oTreeViewItem = (TreeViewItem)oItem; 

      if ((Node)oTreeViewItem.Tag == value) { oResult = oTreeViewItem; break; } 

      if (oTreeViewItem.Items.Count > 0) 
      { 
       oResult = FindNode(oTreeViewItem.Items, value); 

       if (oResult != null) { break; } 
      } 
     } 
     return oResult; 
    } 
+0

MVVM 패턴을 사용하지 않는 특별한 이유가 있습니까? WPFs TreeView는 MVVM과 함께 사용할 때 매우 잘 작동합니다. 그것을 다른 방식으로 사용하면 매우 못 생기고 '이것은 매우 힘들어, 아마도 나는 잘못된 것을하고있는 것입니다.'라는 느낌을 줄 수 있습니다. 특정 태그가있는 TreeViewItem을 찾을 때 코드에서 무엇을 할 계획입니까? – Stipo

+0

내가 상속 한 레거시 코드. 뷰 모델을 받아들이 기 위해 코드 기반을 얻기 위해 스파게티를 교정하려고합니다. (현재 다중 뷰 모델과 코드 숨김이 혼합되어 있습니다.) 견적/미제공보기 모델에서 현재 하드 코딩되어 있기 때문에 항목을 찾아야합니다. – AMissico

답변

0

TreeViewItem이 존재하는지 확인하는 가장 쉬운 방법은 각각의 IsExpanded = "True"를 설정하고 TreeView에서 IsVirtualizing을 False로 설정하는 것입니다. 호기심에서 벗어나 : ItemGenerator를 사용하지 않고 대신 Items 컬렉션을 직접 반복하면 어떻게됩니까? DataTemplate을 사용하지 않으므로 Items 컬렉션에 XAML 파일의 하드 코드 된 항목이 있어야한다고 생각합니다. 항목이 있음을 의미

Class MainWindow 

    Private Sub TestButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) 

     Stop 
     For Each t As TreeViewItem In Me.TestTreeView.Items 
      Debug.Print("Item: {0}, Child count:{1}", t.Header, t.Items.Count) 
     Next 
    End Sub 
End Class 

디버그 창에 출력이

Item: Item 1, Child count:2 
Item: Item 2, Child count:0 

입니다 :

<Window x:Class="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"> 
<StackPanel> 
    <TreeView x:Name="TestTreeView"> 
     <TreeViewItem Header="Item 1"> 
      <TreeViewItem Header="Item 1 1"/> 
      <TreeViewItem Header="Item 1 2"/> 
     </TreeViewItem> 
     <TreeViewItem Header="Item 2"/> 
    </TreeView> 
    <Button x:Name="TestButton" Click="TestButton_Click">Test</Button> 
</StackPanel> 
</Window> 

뒤에 코드 :

나는 다음 테스트를 완료했습니다 심지어 자식 수준에서도 인스턴스화되고 반복 될 수 있습니다. 아마도 당신의 길로 들어가는 것은 실제로 DataTemplates를 사용할 때만 필요한 ItemContainerGenerator입니다. 또한 모든 항목이 인스턴스화되도록하기 위해 윈도우의 Loaded 이벤트가 발생할 때까지 기다려야합니다.

+0

ItemGenerator에 관계없이 첫 번째 항목을 반복 할 수 있습니다. 지금은 다른 레벨로 가려면 "IsExpanded = True"를 사용하고 있습니다. – AMissico

+0

IsVirtualizing = False는 아무런 차이가 없습니다. – AMissico

+0

항목 컬렉션은 하드 코딩 된 항목입니다. – AMissico

1

예는 ItemsControl에있는 항목의 생성을 강제 할 수 있습니다. ItemContainerGenerator에 액세스 한 다음 인터페이스를 명시 적으로 구현하므로 IItemContainerGenerator로 캐스팅합니다. StartAt 및 GenerateNext를 사용하면 항목을 강제로 만들 수 있습니다.

참조 : Why does ItemContainerGenerator return null? 모든 항목에 대해 수행하면됩니다.

+0

작동하려면 코드를 수정할 수 없습니다. 예제를 제공해 줄 수 있습니까? – AMissico

+0

여기 항목 작성을 강제하는 방법에 대한 전체 예제가 있습니다. http://stackoverflow.com/questions/630124/forcing-wpf-to-create-the-items-in-an-itemscontrol –

+0

너무 복잡합니다. 그렇게 어려운 일은 아닙니다. – AMissico