Laden...

Rekursiver TreeView Save/Restore aufgrund des FullPaths

Letzter Beitrag vor 18 Jahren 1 Posts 9.447 Views
Rekursiver TreeView Save/Restore aufgrund des FullPaths

Der folgende TreeView kann seine Hierarchie aufgrund des FullPaths flach speichern und wieder genauso aufbauen.



using System;
using System.Collections;
using System.Windows.Forms;

namespace TreeRestore
{
	/// <summary>
	/// Basierend auf der Idee einen hierarchischen TreeView aufgrund des FullPaths der einzelnen 
	/// TreeNodes flach zu speichern entstand dieses kurze Sample.
	/// 
	/// Idee und Realisierung: Programmierhans
	/// </summary>
	public class TreeRestore : TreeView
	{
		//speichert während des Ladens die bereits erstellten Nodes
		//Key= FullPath (mit PathSeparator am Ende)
		//Value= Node
		private Hashtable _HtNodes=new Hashtable();

		/// <summary>
		/// Constructor
		/// </summary>
		public TreeRestore()
		{
		}

		/// <summary>
		/// Lädt die Daten wieder in den Tree
		/// </summary>
		/// <param name="pStrings">die ArrayList aus SaveToStringArrayList</param>
		public void LoadFromStringArrayList(ArrayList pStrings)
		{
			//Lösche alle Nodes
			this.Nodes.Clear();
			//Lösche den Inhalt der Hashtable
			this._HtNodes.Clear();
			//Sortiere die Strings
			pStrings.Sort();

			foreach (string s in pStrings)
			{
				//Erstelle die Nodes auf Root-Ebene startend rekursiv
				this.CreateNodeOnNodes(this.Nodes,s,string.Empty);
			}
		}

		private void CreateNodeOnNodes(TreeNodeCollection pNodes, string pString, string pParentPath)
		{
			//pString = A1\B1\C1
			//die Hierarchie dieses Nodes (Node C1 hängt an B1 welcher an A1 hängt)
			//z.B:
			//[0]="A1"
			//[1]="B1\C1"
			string[] hierarchy=pString.Split(this.PathSeparator.ToCharArray(),2);
			//key ist der Pfad eines allenfalls schon erstellten Nodes (incl. PathSeparator am Ende)
			//also z.B: A1\
			string relativeKey=string.Concat(hierarchy[0],this.PathSeparator);
			string restString = pString.Replace(relativeKey,string.Empty);
			string key=string.Concat(pParentPath, relativeKey);
			if (restString!=string.Empty)
			{
				
				//wenn der Node A1 (Key = A1\ schon existiert muss an diesem angehängt werden)
				if (this._HtNodes.ContainsKey(key))
				{
					System.Diagnostics.Debug.WriteLine(string.Format("ParamString: {0} \tParentPath: {1} \tNode gefunden: {2} \trekursiver call mit RestString {3}",pString,pParentPath,key,restString));
					pNodes=(TreeNodeCollection)this._HtNodes[key];
					this.CreateNodeOnNodes(pNodes,restString,key);
				}
				else
				{
					System.Diagnostics.Debug.WriteLine(string.Format("ParamString: {0} \tParentPath: {1} \tErstelle Node: {2} \tauf Parent: {3} \tKey: {4}",pString,pParentPath,restString,pParentPath,key));
					//der Node A1 existiert noch nicht also erstelle diesen
					TreeNode nd=new TreeNode(restString);
					pNodes.Add(nd);
					//als Key A1\ adden
					this._HtNodes.Add(key,nd.Nodes);	
				}
			}
		}

		public ArrayList SaveToStringArrayList()
		{
			ArrayList arrRet=new ArrayList();
			this.AddNodes(this.Nodes,arrRet);
			return arrRet;
		}

		private void AddNodes(TreeNodeCollection pNodes, ArrayList pStrings)
		{
			foreach (TreeNode nd in pNodes)
			{
				pStrings.Add(nd.FullPath);
				if (nd.Nodes.Count>0)
				{
					this.AddNodes(nd.Nodes,pStrings);
				}
			}
		}
	}
}


TestCode:



		private void Form1_Load(object sender, System.EventArgs e)
		{

			TreeNode ndA1=new TreeNode("A1");
			this.treeView1.Nodes.Add(ndA1);
			TreeNode ndA2=new TreeNode("A2");
			this.treeView1.Nodes.Add(ndA2);

			TreeNode ndB1=new TreeNode("B1");
			ndA2.Nodes.Add(ndB1);
			TreeNode ndB2=new TreeNode("B2");
			ndA2.Nodes.Add(ndB2);

			TreeNode ndC1=new TreeNode("C1");
			ndB2.Nodes.Add(ndC1);

			TreeNode ndC2=new TreeNode("C2");
			ndB2.Nodes.Add(ndC2);
			

		}

		private void button1_Click(object sender, System.EventArgs e)
		{
			ArrayList arr=this.treeView1.SaveToStringArrayList();
			this.treeView1.LoadFromStringArrayList(arr);
		}



Dies ist eine von vielen Varianten wie man die Position in einer hierarchische Struktur in einem einzigen Feld (z.B: DB) abgespeichert werden kann....

Ausgabe:

ParamString: A1 ParentPath: Erstelle Node: A1 auf Parent: Key: A1\
ParamString: A2 ParentPath: Erstelle Node: A2 auf Parent: Key: A2\
ParamString: A2\B1 ParentPath: Node gefunden: A2\ rekursiver call mit RestString B1
ParamString: B1 ParentPath: A2\ Erstelle Node: B1 auf Parent: A2\ Key: A2\B1\
ParamString: A2\B2 ParentPath: Node gefunden: A2\ rekursiver call mit RestString B2
ParamString: B2 ParentPath: A2\ Erstelle Node: B2 auf Parent: A2\ Key: A2\B2\
ParamString: A2\B2\C1 ParentPath: Node gefunden: A2\ rekursiver call mit RestString B2\C1
ParamString: B2\C1 ParentPath: A2\ Node gefunden: A2\B2\ rekursiver call mit RestString C1
ParamString: C1 ParentPath: A2\B2\ Erstelle Node: C1 auf Parent: A2\B2\ Key: A2\B2\C1\
ParamString: A2\B2\C2 ParentPath: Node gefunden: A2\ rekursiver call mit RestString B2\C2
ParamString: B2\C2 ParentPath: A2\ Node gefunden: A2\B2\ rekursiver call mit RestString C2
ParamString: C2 ParentPath: A2\B2\ Erstelle Node: C2 auf Parent: A2\B2\ Key: A2\B2\C2\

PS: Hoffentlich wird der Backslash-Fehler des Boards irgendwann behoben 😉

Edit: Bitte beachten: Als dieser Beitrag geschrieben wurde, kannte ich erst .Net 1.1 also noch ohne Generics... heute sollte man Generics statt Hashtable verwenden 🙂

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...