Good day, dear gurus .net

I'm trying to make a two-level list based on a TreeView in WinForms . Through the interface of the form designer, you can edit the nodes of the tree, but how to access them programmatically could not understand.

In addition, after editing in the form of an application, I would like to save the entire list of nodes to a file (database). Do visual components and specifically TreeView have a built-in ability to save the state of an object to external storage, or what method can be used for this?

  • WinForms or WPF? - VladD
  • In general, the data itself must be serialized, not the graphic elements. - VladD
  • "how to access them programmatically could not understand." - at run time in a loop, take each tree.Nodes and for each TreeNode ... see my answer. - Stack

2 answers 2

TreeView , like almost all other visual components in WinForms, is wrappers on top of native WinAPI elements.

Almost all native elements in WinAPI are windows. Those. any button is a window.

TreeView , in particular, is a window with a window class WC_TREEVIEW . Any actions with it are not a direct change of some state of control, but indirect, implemented through sending messages to this window. For example, Expand, this is a call of the form

 UnsafeNativeMethods.SendMessage(new HandleRef(tv, tv.Handle), NativeMethods.TVM_EXPAND, NativeMethods.TVE_EXPAND, Handle); 

The state itself is not available in the form of managed objects, and if it is available (in the form of Nodes ), the WinForms developers store it first of all in order to ensure the translation of calls from your code to WinApi.

Accordingly, about the convenience of serialization, they did not bother.

You should clearly separate the data from the view, and use data binding to synchronize changes.

Unfortunately, WinForms is bad enough with hierarchical data binding, so most likely you will have to add your binder . It may be easier to write a stupid serialization of the manual serialization of the Nodes collection.

  • "WinForms is bad enough with hierarchical data binding" - not as good as WPF, but WinForms does too. For example, to edit different levels of xml you need quite a bit of code. An example is in the answer to the question How to bind controls to hierarchical data - Stack
  • @Stack Topicaster asks about the binding of hierarchical data to one control. Your example binds non-hierarchical data (just three related tables) to different controls (just side by side on the form of a separate DataGridView). I do not understand how an example for separate controls and non-hierarchical data shows this same thing "also exists." Can you draw an example with one TreeView and with standard mechanization (i.e. not manually adding nodes?) - PashaPash
  • "your example binds non-hierarchical data" - look carefully at the example. XML is hierarchical data. and controls work with this hierarchy. You say that "for separate controls" , but it is not. just create a WinForms project in Visual Studio and run the sample from the answer. - Stack
  • @Stack what you have answered is Master-Details with three fixed levels. and three separate grids - for the first, second and third levels. This is not a hierarchical databinding :) - PashaPash
  • @Stack try to replace in your example three separate grids with one TreeView. and add a couple more levels to xml. see if it soars or not :) - PashaPash

TreeNode has a Text property that is displayed in the TreeView control. You can save all TreeNode.Text values ​​to xml.

 static void Main(string[] args) { var f = new Form(); var t = CreateTreeView(); t.Parent = f; f.ShowDialog(); Console.WriteLine(GetXml(t.Nodes)); // создать и вывести xml } static TreeView CreateTreeView() { var t = new TreeView() { Dock = DockStyle.Fill }; var n1 = t.Nodes.Add("n1"); n1.Nodes.Add("n11"); var n12 = n1.Nodes.Add("n12"); n12.Nodes.Add("n121"); t.ExpandAll(); return t; } static string GetXml(TreeNodeCollection nodes, bool recursive=true) { var xe = new XElement("tree"); foreach(var n in nodes.OfType<TreeNode>()) ToXml(n, xe, recursive); return xe.ToString(); } static void ToXml(TreeNode n, XElement trg, bool recursive=true) { var xe = new XElement("node", new XAttribute("text", n.Text)); trg.Add(xe); if(recursive) foreach (var c in n.Nodes.OfType<TreeNode>()) ToXml(c, xe, recursive); } 

result

 <tree> <node text="n1"> <node text="n11" /> <node text="n12"> <node text="n121" /> </node> </node> </tree>