Come soluzione non penso proprio sia la più performante, forse è più opportuno fare il filtro a livello di dati al momento del databinding, sfruttando magari Xpath visto che la sorgente è un file XML; per inesperienza su WPF però ho tirato fuori questo giro:

       
        private void cercabox_TextChanged(object sender, TextChangedEventArgs e) {
            treeView.Items.Filter = lookfor;
            FilterAll(treeView);
        }

        private bool lookfor(object obj)
        {
            XmlElement xe = obj as XmlElement;
            foreach (XmlElement x in xe.ChildNodes)
            {
                if (lookfor(x))
                {
                    return true;
                }
            }

            string str = xe.Attributes["Name"].Value;
            if (String.IsNullOrEmpty(str)) return true;
            return str.ToLower().Contains(cercabox.Text.ToLower());
        }

         private void FilterAll(ItemsControl itemsControl)
        {
            ItemContainerGenerator itemContainerGenerator = 
              itemsControl.ItemContainerGenerator;
            for (int i = itemsControl.Items.Count - 1; i >= 0; --i)
            {
                ItemsControl childControl = 
                  itemContainerGenerator.ContainerFromIndex(i) as ItemsControl;
                if (childControl != null)
                {
                    childControl.Items.Filter = lookfor;
                    FilterAll(childControl);
                }
            }
            TreeViewItem treeViewItem = itemsControl as TreeViewItem;
            if (treeViewItem != null)
                treeViewItem.Items.Filter = lookfor;
        }