title: Get the nodes selected in treeview
body: <p>I have a custom treeview class in WPF.
  I wanted to get the selected nodes text in a string list.</p>
  <p><strong>Rules:</strong></p>
  <ul>
  <li><p>If all the nodes in parent is selected, then return the parent node text alone.</p>
  </li>
  <li><p>If all the nodes in parent is not selected, then return a list of <code>parentName_childName</code> of the nodes which is selected.</p>
  <p>The above two rules will apply for all levels. For a treeview with 2 levels of hierarchy return the name as <code>parentName_child1Name_child1ChildName</code>.</p>
  </li>
  </ul>
  <p>Node template c# code:</p>
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.ComponentModel;
  namespace TreeViewCheckBox
  {
      public struct CheckBoxId
      {
          public static string IDCheckBox;
      }
  
      public class Node : INotifyPropertyChanged
      {
          private readonly ObservableCollection&lt;Node&gt; children = new ObservableCollection&lt;Node&gt;();    
          private readonly ObservableCollection&lt;Node&gt; parent = new ObservableCollection&lt;Node&gt;();
          private bool? isChecked = true;
          private bool isExpanded;
          private string text;
          
          public Node()
          {
              this.Id = Guid.NewGuid().ToString();
          }
  
          public event PropertyChangedEventHandler PropertyChanged;
  
          public ObservableCollection&lt;Node&gt; Children
          {
              get { return this.children; }
          }
          public string Id { get; set; }
          public bool? IsChecked
          {
              get { return this.isChecked; }
              set
              {
                  this.isChecked = value;
                  this.RaisePropertyChanged(&quot;IsChecked&quot;);
              }
          }
          public bool IsExpanded
          {
              get { return this.isExpanded; }
              set
              {
                  this.isExpanded = value;
                  this.RaisePropertyChanged(&quot;IsExpanded&quot;);
              }
          }       
          public ObservableCollection&lt;Node&gt; Parent
          {
              get { return this.parent; }
          }
          public string Text
          {
              get { return this.text; }
              set
              {
                  this.text = value;
                  this.RaisePropertyChanged(&quot;Text&quot;);
              }
          }
          private void CheckedTreeChild(IEnumerable&lt;Node&gt; items, int countCheck)
          {
              bool isNull = false;
              foreach (Node paren in items)
              {
                  foreach (Node child in paren.Children)
                  {
                      if (child.IsChecked == true || child.IsChecked == null)
                      {
                          countCheck++;
                          if (child.IsChecked == null)
                          {
                              isNull = true;
                          }
                      }
                  }
                  if (countCheck != paren.Children.Count &amp;&amp; countCheck != 0)
                  {
                      paren.IsChecked = null;
                  }
                  else if (countCheck == 0)
                  {
                      paren.IsChecked = false;
                  }
                  else if (countCheck == paren.Children.Count &amp;&amp; isNull)
                  {
                      paren.IsChecked = null;
                  }
                  else if (countCheck == paren.Children.Count &amp;&amp; !isNull)
                  {
                      paren.IsChecked = true;
                  }
  
                  if (paren.Parent.Count != 0)
                  {
                      this.CheckedTreeChild(paren.Parent, 0);
                  }
              }
          }
          private void CheckedTreeChildMiddle(
              IEnumerable&lt;Node&gt; itemsParent, IEnumerable&lt;Node&gt; itemsChild, bool? isCheckBoxChecked)
          {
              const int CountCheck = 0;
              this.CheckedTreeParent(itemsChild, isCheckBoxChecked);
              this.CheckedTreeChild(itemsParent, CountCheck);
          }
          private void CheckedTreeParent(IEnumerable&lt;Node&gt; items, bool? isCheckBoxChecked)
          {
              foreach (Node item in items)
              {
                  item.IsChecked = isCheckBoxChecked;
                  if (item.Children.Count != 0)
                  {
                      this.CheckedTreeParent(item.Children, isCheckBoxChecked);
                  }
              }
          }
          private void RaisePropertyChanged(string propertyName)
          {
              if (this.PropertyChanged != null)
              {
                  this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
              }
  
              const int CountCheck = 0;
              if (propertyName == &quot;IsChecked&quot;)
              {
                  if (this.Id == CheckBoxId.IDCheckBox &amp;&amp; this.Parent.Count == 0 &amp;&amp; this.Children.Count != 0)
                  {
                      this.CheckedTreeParent(this.Children, this.IsChecked);
                  }
  
                  if (this.Id == CheckBoxId.IDCheckBox &amp;&amp; this.Parent.Count &gt; 0 &amp;&amp; this.Children.Count &gt; 0)
                  {
                      this.CheckedTreeChildMiddle(this.Parent, this.Children, this.IsChecked);
                  }
  
                  if (this.Id == CheckBoxId.IDCheckBox &amp;&amp; this.Parent.Count &gt; 0 &amp;&amp; this.Children.Count == 0)
                  {
                      this.CheckedTreeChild(this.Parent, CountCheck);
                  }
              }
          }
      }
  }
  </code></pre>
  <p>UserControl XAML code:</p>
  <pre><code>&lt;UserControl x:Class=&quot;TreeViewCheckBox.CustomTreeView&quot;
                   xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
                   xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
                   xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
                   xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
                   xmlns:TreeViewWithImageCheckBox=&quot;clr-namespace:TreeViewCheckBox&quot;
                   mc:Ignorable=&quot;d&quot;&gt;
          &lt;UserControl.Resources&gt;
              &lt;HierarchicalDataTemplate DataType=&quot;{x:Type TreeViewCheckBox:Node}&quot; ItemsSource=&quot;{Binding Children}&quot;&gt;
                  &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
                      &lt;StackPanel.Margin&gt;2&lt;/StackPanel.Margin&gt;
                      &lt;CheckBox Margin=&quot;1&quot; IsChecked=&quot;{Binding IsChecked}&quot;
                                PreviewMouseLeftButtonDown=&quot;CheckBox_PreviewMouseLeftButtonDown&quot;
                                Uid=&quot;{Binding Id}&quot; /&gt;
                      &lt;TextBlock Margin=&quot;1&quot; Text=&quot;{Binding Text}&quot; /&gt;
                  &lt;/StackPanel&gt;
              &lt;/HierarchicalDataTemplate&gt;
              &lt;Style TargetType=&quot;TreeViewItem&quot;&gt;
                  &lt;Setter Property=&quot;IsExpanded&quot; Value=&quot;{Binding Path=IsExpanded, Mode=TwoWay}&quot; /&gt;
              &lt;/Style&gt;
          &lt;/UserControl.Resources&gt;
          &lt;Grid&gt;
              &lt;TreeView Name=&quot;tvMain&quot; Grid.ColumnSpan=&quot;2&quot; x:FieldModifier=&quot;private&quot; /&gt;
          &lt;/Grid&gt;
  &lt;/UserControl&gt;
  </code></pre>
  <p>UserControl c# code:</p>
  <pre><code>using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.Data;
  using System.Linq;
  using System.Windows.Controls;
  namespace TreeViewCheckBox
  {
      public partial class CustomTreeView
      {
          public CustomTreeView()
          {
              this.Nodes = new ObservableCollection&lt;Node&gt;();
              this.InitializeComponent();
              this.FillTree();
          }
          private ObservableCollection&lt;Node&gt; Nodes { get; set; }
  
          public void FillTree()
          {
              this.Nodes.Clear();
              for (int i = 0; i &lt; 5; i++)
              {
                  var level1Items = new Node { Text = &quot; Level 1 Item &quot; + (i + 1) };
                  for (int j = 0; j &lt; 2; j++)
                  {
                      var level2Items = new Node { Text = &quot; Level 2 Item &quot; + (j + 1) };
                      level2Items.Parent.Add(level1Items);
                      level1Items.Children.Add(level2Items);
                      for (int n = 0; n &lt; 2; n++)
                      {
                          var level3Items = new Node { Text = &quot; Level 3 Item &quot; + (n + 1) };
                          level3Items.Parent.Add(level2Items);
                          level2Items.Children.Add(level3Items);
                      }
                  }
  
                  this.Nodes.Add(level1Items);
              }
  
              this.tvMain.ItemsSource = this.Nodes;
          }
  
          private void CheckBox_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
          {
              var currentCheckBox = (CheckBox)sender;
              CheckBoxId.IDCheckBox = currentCheckBox.Uid;
          }
      }
     }
  </code></pre>
  <p>How to get the selected nodes in a List?</p>