private void ShowXNode(XNode xnode, TreeViewItemXNode parentNode, int position = -1)
        {
            var newItem = new TreeViewItemXNode();

              newItem.XNode = xnode;

              if (typeof(XComment).IsAssignableFrom(xnode.GetType())) {
            var comment = (XComment)xnode;

            newItem.Header = comment.Value;

              } else if (typeof(XElement).IsAssignableFrom(xnode.GetType())) {
            var element = (XElement)xnode;

            //TreeViewItem to close opening tag.
            newItem.EndingItem = new TreeViewItemXNode();
            newItem.EndingItem.XNode = element;
            newItem.EndingItem.BeginItem = newItem;
            newItem.EndingItem.Header = "</" + element.Name + ">";

            if (element.HasElements) {
              var elementsEnumerator = element.Nodes().GetEnumerator();

              while (elementsEnumerator.MoveNext()) {
            this.ShowXNode(elementsEnumerator.Current, newItem);
              }
            } else if (element.Value.Length > 0) {
              //TreeViewItem to show element value.
              //When an XElement has a value, it has an XText node, which is in the first position.
              newItem.ValueItem = new TreeViewItemXNode();
              newItem.ValueItem.BeginItem = newItem;
              newItem.ValueItem.XNode = element.FirstNode;
              newItem.ValueItem.Header = element.Value;
              newItem.Items.Add(newItem.ValueItem);
            }

            if (newItem.ValueItem == null) {
              //Create an XNode to hold the element's value.
              var text = new XText("");
              element.AddFirst(text);

              //TreeViewItem to show element value.
              newItem.ValueItem = new TreeViewItemXNode();
              newItem.ValueItem.BeginItem = newItem;
              newItem.ValueItem.XNode = text;
              newItem.ValueItem.Header = "";
            }

            this.RefreshXElementItemHeader(newItem);

              } else if (typeof(XText).IsAssignableFrom(xnode.GetType())) {
            var text = (XText)xnode;

            newItem.BeginItem = parentNode;
            newItem.Header = text.Value;
            parentNode.ValueItem = newItem;

              } else {
            newItem.Header = "UNKNOWN XNODE!!!";
              }

              if (parentNode == null)
            tvXmlDocument.Items.Add(newItem);
              else {
            if (position == -1)
              parentNode.Items.Add(newItem);
            else
              parentNode.Items.Insert(position, newItem);
              }

              if (newItem.HasItems) {
            newItem.Collapsed += new RoutedEventHandler(ItemCollapsed);
            newItem.Expanded += new RoutedEventHandler(ItemExpanded);
              }
        }
        private void tvXmlDocument_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var selectedItem = (TreeViewItemXNode)tvXmlDocument.SelectedItem;

              txNodeName.TextChanged -= new TextChangedEventHandler(txNodeName_TextChanged);
              txNodeName.GotFocus -= new RoutedEventHandler(txNodeName_GotFocus);
              txNodeValue.TextChanged -= new TextChangedEventHandler(txNodeValue_TextChanged);

              if (selectedItem == null) {
            grdNodeDetails.Visibility = Visibility.Hidden;
            mSelectedItem = null;
            mSelectedXNode = null;

              } else {
            grdNodeDetails.Visibility = Visibility.Visible;

            /*if (selectedItem.EndingItem != null || (selectedItem.BeginItem == null && selectedItem.EndingItem == null)) {
              //This is item is an XElement because it either:
              //  has ending item, which only XElement items can have; OR
              //  doesn't have either a begin item or an end item, which only XElement items cannot have both.
              //Do nothing, just let execution fall through.
            } else*/ if (selectedItem.BeginItem != null) {
              //The real item is the one at the beginning.
              selectedItem = selectedItem.BeginItem;
            }

            if (selectedItem != mSelectedItem) {
              //Selected item is different from the previously selected one.
              mSelectedItem = selectedItem;
              mSelectedXNode = mSelectedItem.XNode;

              mAttributeRows.Clear();
              grdAttributes.Children.Clear();
              grdAttributes.RowDefinitions.Clear();

              if (typeof(XComment).IsAssignableFrom(mSelectedXNode.GetType())) {
            //User selected a comment. Only its value can be changed.
            var comment = (XComment)mSelectedXNode;

            lbNodeType.Text = "This is a comment node. Only its value can be changed.";
            grpAttributes.Visibility = Visibility.Hidden;
            txNodeValue.Text = comment.Value;
            txNodeName.IsEnabled = false;
            txNodeName.Text = "Comment Node";

            txNodeName.TextChanged -= new TextChangedEventHandler(txNodeName_TextChanged);
            txNodeName.GotFocus -= new RoutedEventHandler(txNodeName_GotFocus);
            txNodeValue.TextChanged += new TextChangedEventHandler(txNodeValue_TextChanged);

              } else if (typeof(XElement).IsAssignableFrom(mSelectedXNode.GetType())) {
            var element = (XElement)mSelectedXNode;
            XAttributeGridRow newRow;

            lbNodeType.Text = "This is a normal node. You can change its name, value, and attributes.";
            txNodeName.IsEnabled = true;
            txNodeName.Text = element.Name.LocalName;
            txNodeValue.Text = (string)mSelectedItem.ValueItem.Header;

            grpAttributes.Visibility = Visibility.Visible;

            if (element.HasAttributes) {
              using (var attributesEnumerator = element.Attributes().GetEnumerator()) {
                while (attributesEnumerator.MoveNext()) {
                  newRow = new XAttributeGridRow();

                  newRow.XAttribute = attributesEnumerator.Current;
                  newRow.AddToGrid(grdAttributes);
                  newRow.XAttributeValueChanged += new EventHandler(this.XAttribute_ValueChanged);

                  mAttributeRows.Add(newRow);
                }
              }
            }

            txNodeName.TextChanged += new TextChangedEventHandler(txNodeName_TextChanged);
            txNodeName.GotFocus += new RoutedEventHandler(txNodeName_GotFocus);
            txNodeValue.TextChanged += new TextChangedEventHandler(txNodeValue_TextChanged);
              }

            } else if (typeof(XComment).IsAssignableFrom(mSelectedXNode.GetType())) {
              txNodeName.TextChanged -= new TextChangedEventHandler(txNodeName_TextChanged);
              txNodeName.GotFocus -= new RoutedEventHandler(txNodeName_GotFocus);
              txNodeValue.TextChanged += new TextChangedEventHandler(txNodeValue_TextChanged);

            } else if (typeof(XElement).IsAssignableFrom(mSelectedXNode.GetType())) {
              txNodeName.TextChanged += new TextChangedEventHandler(txNodeName_TextChanged);
              txNodeName.GotFocus += new RoutedEventHandler(txNodeName_GotFocus);
              txNodeValue.TextChanged += new TextChangedEventHandler(txNodeValue_TextChanged);

            }
              }
        }
        private void RefreshXElementItemHeader(TreeViewItemXNode item)
        {
            var element = (XElement)item.XNode;
              var newItemHeader = "<" + element.Name;

              if (element.HasAttributes) {
            using (var attEnumerator = element.Attributes().GetEnumerator()) {
              while (attEnumerator.MoveNext()) {
            newItemHeader += " " + attEnumerator.Current.Name + "=" + attEnumerator.Current.Value;
              }
            }
              }

              if (!item.HasItems)
            newItemHeader += "/";

              item.Header = newItemHeader + ">";
        }