2012-04-30 3 views
2

Я пытаюсь найти конкретное значение TreeViewItem, у которого Tag свойство имеет значение. Ниже FindNode работает только для элементов первого уровня или на других уровнях, если родительский TreeViewItem расширен. В приведенном ниже примере, если «FFF» расширен, то FindNode работает так, как ожидалось. Я предполагаю, что ContainerFromItem возвращает значение null, потому что элементы не были созданы. Есть ли способ заставить все TreeViewItems создать?Как найти 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? WPFs TreeView отлично работает при использовании с MVVM. Использование этого по-другому может быть очень уродливым и дать вам ощущение «это так сложно, я, вероятно, что-то не так». Что вы планируете делать в своем коде, когда найдете TreeViewItem с определенным тегом? – Stipo

+0

Устаревший код, который я унаследовал. Я пытаюсь выпрямить спагетти, чтобы получить форму кода в форме, чтобы принять модель представления. (В настоящее время существует смесь нескольких моделей просмотров и кода.) Мне нужно найти элементы, потому что они в настоящее время жестко закодированы в модели представлений quote/un-quote. – AMissico

ответ

0

Самый простой способ убедиться, что ваши TreeViewItems существуют, вероятно, для установки IsExpanded = «True» на каждом из них и для установки IsVirtualizing в False в TreeView. Просто из любопытства: что произойдет, если вы не используете ItemGenerator, а просто перейдете в коллекцию Items напрямую? Поскольку вы не используете DataTemplate, я бы предположил, что коллекция Items должна содержать жестко закодированные элементы из вашего файла XAML.

Я сделал следующий тест:

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

и код позади:

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 

, что означает, что элементы экземпляр и может быть повторен, даже на уровне ребенка. Вероятно, что вам мешает, это ItemContainerGenerator, который на самом деле нужен только при использовании DataTemplates. Кроме того, вам, вероятно, придется ждать, пока после события «Загружено» окна не будет создано все элементы.

+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