title: Filtering a hierarchical object displayed with nested xaml data templates
body: <p>I'm having trouble filtering hierarchical data that's being displayed in nested xaml templates.</p>
  
  <p>I've got a <code>ObservableCollection&lt;Foo&gt; Foos</code>, that I'm displaying in XAML.</p>
  
  <p>Lets say Foo looks like:</p>
  
  <pre><code>class Foo
  {
      public ObservableCollection&lt;Bar&gt; Bars;
  }
  
  class Bar
  {
      public ObservableCollection&lt;Qux&gt; Quxes;
  }
  </code></pre>
  
  <p>I'm displaying Foos with the following xaml:</p>
  
  <pre><code>&lt;Grid&gt;
      &lt;Grid.Resources&gt;
          &lt;CollectionViewSource x:Key="MyCVS" Source="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.UnifiedSymbols}" Filter="MyCVS_Filter" /&gt;
  
          &lt;DataTemplate x:Key="NestedTabHeaderTemplate"&gt;
              &lt;TextBlock Text="{Binding Path=Name}"/&gt;
          &lt;/DataTemplate&gt;
          &lt;DataTemplate x:Key="NestedTabContentTemplate"&gt;
              &lt;ListBox ItemsSource="{Binding Path=Quxes}" DisplayMemberPath="Name"/&gt;
          &lt;/DataTemplate&gt;
  
          &lt;DataTemplate x:Key="TopLevelTabHeaderTemplate"&gt;
              &lt;TextBlock Text="{Binding Path=Name}"/&gt;
          &lt;/DataTemplate&gt;
          &lt;DataTemplate x:Key="TopLevelTabContentTemplate"&gt;
              &lt;TabControl ItemsSource="{Binding Path=Bars}"
                          ItemTemplate="{StaticResource NestedTabHeaderTemplate}" 
                          ContentTemplate="{StaticResource NestedTabContentTemplate}"
                          /&gt;
          &lt;/DataTemplate&gt;
      &lt;/Grid.Resources&gt;
  
      &lt;TabControl ItemSource="{Binding correct binding for my control's collection of Foos}"
                  ItemTemplate="{StaticResource TopLevelTabHeaderTemplate}" 
                  ContentTemplate="{StaticResource TopLevelTabContentTemplate}"
                              x:Name="tabControl"
                  /&gt;
  &lt;/Grid&gt;
  </code></pre>
  
  <p>To put it into words, there's a tab control, with a tab for each Foo.  Each Foo is a tab control, with each Bar it contains in it's own tab.  Each Bar contain's a listbox of its Quxes.</p>
  
  <p>or:</p>
  
  <pre><code> ______ ______ ______  
  | Foo1 | Foo2 | Foo3 |  
  |______ ______       |  
  | Bar1 | Bar2 |______|  
  | | qux1            ||  
  | | qux2            ||  
  | | qux3            ||  
  ---------------------- 
  </code></pre>
  
  <p>I also have a TextBox that I'd like to use to filter this breakdown.  <strong>When I type in the text box, I'd like to filter the quxes so those not containing the text wouldn't be visible.</strong>  Ideally <code>Bar</code> tabs would also be hidden if they have no visible quxes, and <code>Foo</code> tabs hidden when they have no visible <code>Bar</code>s</p>
  
  <p>I have considered two approaches:</p>
  
  <h2>Approach 1, reset the Filter property on the appropriate CollectionViewSources</h2>
  
  <p>On my text box's TextChanged event, I loop through my Foo's asking for the corresponding (static) TabControl's CollectionViewSource:</p>
  
  <pre><code>foreach(Foo foo in tabControl.Items)
  {
      var tabItem = tabControl.ItemContainerGenerator.ContainerFromItem(foo);    // This is always of type TabItem
      // How do I get the TabControl that will belong to each of Foo's Bar's?
  }
  </code></pre>
  
  <h2>Approach 2, declare the ListView's ItemSource to a CollectionViewSource</h2>
  
  <p>I tried setting the Filter via xaml, by changing this line:</p>
  
  <pre><code>&lt;ListBox ItemsSource="{Binding Path=Quxes}" DisplayMemberPath="Name"&gt;
  </code></pre>
  
  <p>to this,</p>
  
  <pre><code>&lt;CollectionViewSource x:Key="MyCVS" Source="?????" Filter="MyCVS_Filter" /&gt;
  ...
  &lt;ListBox ItemsSource="{Binding Source={StaticResource MyCVS}}" DisplayMemberPath="Name"&gt;
  </code></pre>
  
  <p>I've tried a number of things where I have "?????" but I cannot correctly bind to the ListBox's datacontext and appropriate Quxes member.  Nothing I try results in the quxes being displayed, and I get no errors on the console.  Even If I could get this approach to work, I'm not sure how I would re-trigger this filter when the text in the search box changed.</p>
  
  <p>Any advice or direction would be appreciated.</p>