📜 ⬆️ ⬇️

.NET component - Tree View with search

When the TreeView needed to do a search, I made the search implementation out of control, and then set its SelectedItem property.
Unfortunately, the standard WPF TreeView control has the SelectedItem property read-only.
Therefore, I had to enter the IsSelected and IsExpanded properties into each object and associate these properties with the corresponding TreeViewItem property. ( usually this is recommended in the internet )
Thus, you only need to set the desired IsSelected object, and all its ancestors IsExpanded .
This implementation works great, but ...
  1. It is not very nice to have a business object IsSelected and IsExpanded. And to create a twist model for each item in the tree is a chore.
  2. The search for the tree should be implemented every time in the code, which as a minimum takes time and ... hassle in one word.


In general, after thinking a little, I came to this concept.


This is how I searched all templates. It's all relatively simple.
public override void OnApplyTemplate() { base.OnApplyTemplate(); templateDescrColl = new TemplateDescriptionCollection();//    List<FrameworkElement> parents= Helper.GetAllParent(this);//    FindDataTemplatesResources(this.Resources);//      foreach (FrameworkElement parent in parents) //     { FindDataTemplatesResources(parent.Resources); } FindDataTemplatesResources(System.Windows.Application.Current.Resources);//      } 

Here is the logic of the search for patterns, everything is as planned here, except that there is an alternative way of defining search paths.
This may be necessary on the one hand because the binding search does not always work.
(in the case when a separate control is used to display a node with its rather complex logic it does not work exactly).
Well, on the other hand, sometimes you need to more accurately specify the path to search.
The path is set via the FindPatches property as a string "TypeName1: Property1, Property2 TypeName2:"
In this case, for the TypeName1 type, the property1, Property2 properties will be searched, and the TypeName2 property search will not be performed at all.
  private void FindDataTemplatesResources(ResourceDictionary Resource) { foreach (object xxx in Resource.Values) { DataTemplate dataTemplate = xxx as DataTemplate; if (dataTemplate != null)//  a DataTemplate { bool hierarhical=false; if (!templateDescrColl.ExistType(dataTemplate.DataType as Type, out hierarhical))//     { TemplateBindingDescr templateBindingDescr = new TemplateBindingDescr();// HierarchicalDataTemplate hdt = xxx as HierarchicalDataTemplate;//  HierarchicalDataTemplate here if (hdt != null) { Binding ItemsSourceBinding = hdt.ItemsSource as Binding; string ItemsSourcePath = ItemsSourceBinding.Path.Path; templateBindingDescr.itemSourcePath = ItemsSourcePath;//       templateBindingDescr.IsHierathical = true; } Type tType = dataTemplate.DataType as Type; templateBindingDescr.TargetType = tType; // type  if (! String.IsNullOrWhiteSpace (FindPatches) && FindPatches.Contains (tType.Name + ":")) //       { Match match = Regex.Match (FindPatches, tType.Name + ":([^:]*)");. if (match.Success) { string re = match.Groups [1]. Value; string [] pathes = re.Split (','); templateBindingDescr.BindingPathes.AddRange (pathes); } } else //       { FrameworkElement frameworkElement = dataTemplate.LoadContent () as FrameworkElement; //   List <FrameworkElement> DependencyObjects = Helper.GetAllVisualChildren (frameworkElement);//     if (DependencyObjects!= null) { foreach (FrameworkElement dependencyObject in DependencyObjects) { //    BindingExpression BE = System.Windows.Data.BindingOperations.GetBindingExpression (dependencyObject, TextBlock.TextProperty); if (BE!= null) { string path = BE.ParentBinding.Path.Path; templateBindingDescr.BindingPathes.Add (path); } } } } templateDescrColl.Add (templateBindingDescr); //    } } } } 

Here is the search for all elements containing the search text.
  /// <summary> ///                     FindText ///    /// </summary> /// <param name="control"></param> /// <param name="FindText"></param> /// <returns></returns> public List<NamedObject> FindObjectByPropertyNames(IEnumerable itemsSource, List<int> path) { List<NamedObject> ret = new List<NamedObject>();//       int i = 0; path.Add(i);//      foreach (object Item in itemsSource) //    { path[path.Count - 1] = i;//      TemplateBindingDescr desctiption= templateDescrColl.Get(Item.GetType());//        string subItemsPath=desctiption.itemSourcePath;//      string ObjectText=String.Empty;//           bool ok=false; foreach (string findPath in desctiption.BindingPathes)//         { object ItemVal = Item.GetObjectSubItem(findPath); //    if (ItemVal != null )//    { string ItemText = ItemVal.ToString().ToUpper();//    ObjectText += ItemText + " "; if (ItemText.Contains(FindText.ToUpper())) { ok = true; //      } } } if (ok)//     { List<int> path2 = new List<int>(); path2.AddRange(path); ret.Add(new NamedObject() { Name = ObjectText, Item = Item, Path = path2 });//     } if (subItemsPath != null)//      { IEnumerable subItems=Item.GetObjectSubItem(subItemsPath) as IEnumerable; if (subItems != null) { List<int> path1 = new List<int>(); path1.AddRange(path); ret.AddRange(FindObjectByPropertyNames(subItems, path1)); } } i++; } return ret; } 

Here is the search for all elements containing the search text.
 int failCount; //   //    void SelectNodeByPath(ItemsControl control, IEnumerable<int> path) { List<int>L= path.ToList<int>(); if (L.Count == 0) { return; } if (control.Items.Count > L[0]) { do //         { control.UpdateLayout(); } while (control.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated); TreeViewItem dObject = control.ItemContainerGenerator.ContainerFromIndex(L[0]) as TreeViewItem; if (dObject == null)//       { dObject = GetTreeViewItem(control, L [0]); } if (dObject == null) { MessageBox.Show("   ); } else //  { L.RemoveAt(0); if (L.Count == 0) //       { dObject.IsSelected = true; dObject.BringIntoView(); } else //        { dObject.IsExpanded = true; SelectNodeByPath(dObject, L); //   } } } else { MessageBox.Show(" "+control.Items.Count+"   > "+L[0]); } } 

')
GetTreeViewItem function (control, L [0]); allowing you to reliably find the node made thanks
Deranged thanks a lot to him. Based on the code from the specified site.
blogs.msdn.com/b/wpfsdk/archive/2010/02/23/finding-an-object-treeviewitem.aspx
Here is the new code.
myTreeViewWith search.zip
Search works in a separate thread.

It is possible to do an advanced search so that the user can select the properties by which to search.
and ... But this is a decorating idea here and it works.
PS The author of the post, my brother SergejSh - all questions and comments to him.

Source: https://habr.com/ru/post/135274/


All Articles