title: WPF: get all list of specified controls from DataGrid.RowDetailsTemplate
body: <p>I have main <code>DataGrid</code> for displaying a list of documents.
  This <code>MainGrid</code> has <code>DataGrid.RowDetailsTemplate</code> specified in <code>XAML</code>.</p>
  
  <p>This <code>DataGrid.RowDetailsTemplate</code> contains one more (inner or nested) <code>DataGrid</code>s.</p>
  
  <p>So each row of <code>MainGrid</code> contains <code>DataGrid.RowDetailsTemplate</code> with inner <code>DataGrid</code>.</p>
  
  <p>I need to get list of all inner (nested) <code>DataGrid</code>s having only the <code>MainGrid</code> reference.
  I've tried Visual/Logil Tree helpers, but both returns nothing for GetChildren calls...</p>
  
  <p>What is the way to get nested <code>DataGrid</code> from <code>DataGrid.RowDetails</code>?</p>
  
  <p>Repro steps:
  1) Create Windows Desktop -> WPF Application (empty) in Visual Studio 2013 or higher
  2) Use code samples below:</p>
  
  <p>MainWindow.xaml</p>
  
  <pre><code>&lt;Window x:Class="ExampleNestedGrid.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"&gt;
      &lt;Grid&gt;
  
          &lt;Grid.RowDefinitions&gt;
              &lt;RowDefinition Height="Auto"/&gt;
              &lt;RowDefinition Height="*"/&gt;
          &lt;/Grid.RowDefinitions&gt;
  
          &lt;ToolBar Grid.Row="0" Header="Action:"&gt;
              &lt;Button x:Name="RefreshBtn" Command="{Binding RefreshCommand}"&gt;Refresh&lt;/Button&gt;
          &lt;/ToolBar&gt;
  
          &lt;DataGrid x:Name="MainGrid" ItemsSource="{Binding Documents}" AutoGenerateColumns="False" Grid.Row="1"&gt;
              &lt;DataGrid.Columns&gt;
                  &lt;DataGridTextColumn Binding="{Binding Name, Mode=OneWay}" Width="*"/&gt;
                  &lt;DataGridTextColumn Binding="{Binding Number, Mode=OneWay}" Width="*"/&gt;
              &lt;/DataGrid.Columns&gt;
  
              &lt;DataGrid.RowDetailsTemplate&gt;
                  &lt;DataTemplate&gt;
                      &lt;Grid&gt;
                          &lt;DataGrid x:Name="NestedGrid" ItemsSource="{Binding LinkedEmployees}" AutoGenerateColumns="False"&gt;
                              &lt;DataGrid.Columns&gt;
                                  &lt;DataGridTextColumn Binding="{Binding Id, Mode=OneWay}" Width="150"/&gt;
                                  &lt;DataGridTextColumn Binding="{Binding Name, Mode=OneWay}" Width="150"/&gt;
                                  &lt;DataGridTextColumn Binding="{Binding Status, Mode=OneWay}" Width="150"/&gt;
                              &lt;/DataGrid.Columns&gt;
                          &lt;/DataGrid&gt;
                      &lt;/Grid&gt;
                  &lt;/DataTemplate&gt;
              &lt;/DataGrid.RowDetailsTemplate&gt;
          &lt;/DataGrid&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>MainWindow.xaml.cs</p>
  
  <pre><code>using System.Collections.ObjectModel;
  using System.ComponentModel;
  using System.Runtime.CompilerServices;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Input;
  
  namespace ExampleNestedGrid
  {
      /// &lt;summary&gt;
      /// Interaction logic for MainWindow.xaml
      /// &lt;/summary&gt;
      public partial class MainWindow : Window
      {
          public MainWindow()
          {
              InitializeComponent();
  
              DataContext = new DisplayViewModel(MainGrid);
          }
      }
  
      public class DisplayViewModel : PropertyBase
      {
          private DataGrid MainGrid;
  
          public DisplayViewModel(DataGrid MainGrid) 
          {
              this.MainGrid = MainGrid;
  
              Documents = new ObservableCollection&lt;Document&gt;();
              LinkedEmployee empl1 = new LinkedEmployee("1", "Ben");
              LinkedEmployee empl2 = new LinkedEmployee("2", "John");
  
              Document doc = new Document("first", "111");
              doc.LinkedEmployees.Add(empl1);
              doc.LinkedEmployees.Add(empl2);
  
              Documents.Add(doc);
  
              RefreshCommand = new RefreshCommand(Documents, MainGrid);
          }
  
          public ObservableCollection&lt;Document&gt; Documents { get; set; }
          public ICommand RefreshCommand { get; set; }
      }
  
      public sealed class LinkedEmployee : PropertyBase
      {
          public LinkedEmployee(string id, string name)
          {
              _id = id;
              _name = name;
          }
  
          public void Update(string name)
          {
              Name = name;
          }
  
          private string _id;
          private string _name;
          private bool _status;
  
          public bool Status 
          {
              get { return _status; }
              set
              {
                  _status = value;
                  OnPropertyChanged();
              }
          }
  
          public string Id
          {
              get { return _id; }
              set
              {
                  _id = value;
                  OnPropertyChanged();
              }
          }
  
          public string Name
          {
              get { return _name; }
              set
              {
                  _name = value;
                  OnPropertyChanged();
              }
          }
      }
  
      public class Document : PropertyBase
      {
          public Document(string name, string number)
          {
              _name = name;
              _number = number;
  
              LinkedEmployees = new ObservableCollection&lt;LinkedEmployee&gt;();
          }
  
          public void Update(string number)
          {
              Number = number;
          }
  
          private string _name;
          private string _number;
  
          public virtual string Name
          {
              get { return _name; }
              set
              {
                  _name = value;
                  OnPropertyChanged();
              }
          }
  
          public virtual string Number
          {
              get { return _number; }
              set
              {
                  _number = value;
                  OnPropertyChanged();
              }
          }
  
          public ObservableCollection&lt;LinkedEmployee&gt; LinkedEmployees { get; set; }
      }
  
      public abstract class PropertyBase : INotifyPropertyChanged
      {
          #region public properties
          public event PropertyChangedEventHandler PropertyChanged;
          #endregion
  
          #region protected methods
          protected void OnPropertyChanged([CallerMemberName]string caller = null)
          {
              if (PropertyChanged != null)
                  PropertyChanged.Invoke(this, new PropertyChangedEventArgs(caller));
          }
          #endregion
      }
  }
  </code></pre>
  
  <p>RefreshCommand.cs</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.ComponentModel;
  using System.Linq;
  using System.Text;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Input;
  using System.Windows.Media;
  
  namespace ExampleNestedGrid
  {
      public class RefreshCommand : ICommand
      {
          private ObservableCollection&lt;Document&gt; Documents;
          private System.Windows.Controls.DataGrid MainGrid;
  
          #region public methods
          public event EventHandler CanExecuteChanged
          {
              add { CommandManager.RequerySuggested += value; }
              remove { CommandManager.RequerySuggested -= value; }
          }
          #endregion
  
          #region public methods
  
          public RefreshCommand(ObservableCollection&lt;Document&gt; Documents, System.Windows.Controls.DataGrid MainGrid)
          {
              // TODO: Complete member initialization
              this.Documents = Documents;
              this.MainGrid = MainGrid;
          }
  
          public void Execute(object parameter)
          {
              Documents.First().LinkedEmployees.First().Status = !Documents.First().LinkedEmployees.First().Status;
  
              ICollectionView view = CollectionViewSource.GetDefaultView(Documents);
              view.Filter = (item) =&gt; item != null;
  
              MainGrid.ItemsSource = view;
  
              var childGrids = FindVisualChildren&lt;DataGrid&gt;(MainGrid);
              foreach (DataGrid childGrid in childGrids)
              {
                  MessageBox.Show(childGrid.Name);
              }
          }
  
          public bool CanExecute(object parameter)
          {
              return Documents != null &amp;&amp; MainGrid != null;
          }
          #endregion
  
          private static IEnumerable&lt;T&gt; FindVisualChildren&lt;T&gt;(DependencyObject depObj) where T : DependencyObject
          {
              if (depObj != null)
              {
                  for (int i = 0; i &lt; VisualTreeHelper.GetChildrenCount(depObj); i++)
                  {
                      DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                      if (child != null &amp;&amp; child is T)
                      {
                          yield return (T)child;
                      }
  
                      foreach (T childOfChild in FindVisualChildren&lt;T&gt;(child))
                      {
                          yield return childOfChild;
                      }
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>3) Start application. Click on first row. Row Details should expand.</p>
  
  <p>4) Sort main row by first column</p>
  
  <p>5) Sort row details by second column</p>
  
  <p>6) Click refresh button</p>
  
  <p>7) Check that sorting indicator disappeared.</p>
  
  <p>8) Check that no message box appeared that should fire about found nested data grids.
  <a href="https://i.stack.imgur.com/RlrRx.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/RlrRx.jpg" alt="enter image description here"></a></p>