2012-04-30 19 views
2

Tagプロパティが特定の値に設定されている特定のTreeViewItemを検索しようとしています。 FindNodeは、親がTreeViewItemが展開されている場合、最初のレベルのアイテムまたは他のレベルでのみ機能します。次の例では、 "FFF"を展開すると、FindNodeが期待通りに機能します。アイテムが作成されていないため、ContainerFromItemがnullを返すと仮定しています。すべてのTreeViewItemを強制的に作成する方法はありますか?Tagプロパティで特定の値を持つTreeViewItemを見つけるにはどうすればいいですか

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

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

hbarckの回答に基づいて正しいFindNode実装は次のとおりです。

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パターンを使用しない特別な理由はありますか? WPF 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> 

と背後にあるコード:

私は次のテストを行ってきましたインスタンス化され、子レベルでも反復処理が可能です。おそらくあなたの方法になるのはItemContainerGeneratorですが、これは実際にはDataTemplatesを使用している場合にのみ必要です。また、すべての項目をインスタンス化するには、ウィンドウの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

関連する問題