Solved

How to sort a treeview alfabeticly

Posted on 2011-03-16
10
738 Views
Last Modified: 2013-12-17
Hi,

On my form I have a treeview on the left and a textbox on the right devided with a splitter.
The treeview nodes are loaded and saved to/from a database. It all works fine.
But the only thing the treeview doesn't do is to sort its nodes alphabeticly.

I have searched and searched but couldn't find the problem on my own.  So i don't know if the
code is allready there to sort the nodes alfabeticly. What I do know is that if its there
it doesn't work. Who can help me with this example.

Peter
namespace DbTreeView
{
    public partial class MainForm : Form
    {
        private ContextMenu tvSampleMenu = new ContextMenu();
        private const string ImageIndexColumnName = "ImageIndex";
        private const string SelectedImageIndexColumnName = "SelectedImageIndex";
        private const string SortOrderColumnName = "SortOrder";
        private string DBName = "";
        private string DBConStr = "";

        public MainForm()
        {
            InitializeComponent();
        }
        //*----------------------------------------------------------*//
        private void MainForm_Load(object sender, EventArgs e)
        {
            Hourglass(true);
            try
         {
        DBName = Application.StartupPath + @"\DBRoot.mdb";
        DBConStr = @"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";Data Source=" + DBName +";";
        tvSampleMenu.MenuItems.Add("Add Folder", new EventHandler(tvSampleRightClickInsFolder));
        LoadTree(tvNotes, GetHierarchy(DBConStr, 1));
         }
         catch (Exception err) { Hourglass(false); MessageBox.Show(err.Message); }
         finally { Hourglass(false); }
        }
        //*----------------------------------------------------------*//
        private void LoadTree(TreeView tv, DataSet ds)
        {
            Hourglass(true);
            try
            {
                LoadFromDataSet(tv, ds, "Description");
                if (tv.Nodes.Count > 0)
                {
                    tv.Nodes[0].Expand();
                }
            }
            catch (Exception) { throw; }
            finally { Hourglass(false); }
        }
        //*----------------------------------------------------------*//
        public static DataSet GetHierarchy(string connectionString, int modelID)
        {
            string sql = "";
            DataSet ds = null;
            try
            {
                sql = "select * from hierarchy ";
                sql += "  where modelid=" + modelID.ToString();
                sql += "  order by parentnodeid,sortorder asc";
                ds = GetDataSet(connectionString, sql);
                SetHierarchyRelationships(ds);
            }
            catch (Exception) { throw; }
            return ds;
        }
        //*----------------------------------------------------------*//
        public static void SetHierarchyRelationships(DataSet ds)
        {
            DataColumn fk;
            DataColumn[] pk = new DataColumn[1];
            ForeignKeyConstraint fkcdelete;
            DataRelation relation;
            string datarelationname = "ParentChild";
            try
            {
                ds.Tables[0].TableName = "Hierarchy";
                pk[0] = ds.Tables[0].Columns["NodeID"];
                fk = ds.Tables[0].Columns["ParentNodeID"];
                ds.Tables[0].PrimaryKey = pk;
                fkcdelete = new ForeignKeyConstraint(pk[0], fk);
                fkcdelete.DeleteRule = Rule.Cascade;
                relation = new DataRelation(datarelationname, pk[0], fk, false);
                ds.Tables[0].Constraints.Add(fkcdelete);
                ds.Tables[0].AcceptChanges();
                ds.Relations.Add(relation);
            }
            catch (Exception) { throw; }
            return;
        }
        //*----------------------------------------------------------*//
        public static bool CommitHierarchy(string connectionString, DataSet ds)
        {
            string sql = "";
            bool ret = false;
            int ModelID = 0;
            DataTable dt;
            try
            {
                if (ds.Tables.Count < 1) { return ret; }
                dt = ds.Tables[0];
                ModelID = int.Parse(dt.Rows[0]["ModelID"].ToString());
                sql = "select  * from Hierarchy where ModelID = " + ModelID.ToString();
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    if (dt.Rows[i].RowState.ToString() == "Deleted") { continue; }
                    if (int.Parse(dt.Rows[i]["ModelID"].ToString()) != ModelID)
                    {
                        dt.Rows[i]["ModelID"] = ModelID;
                    }
                }
                CommitToDataBase(connectionString, ds, sql);
                ret = true;
            }
            catch (Exception e)
            {
                //Debug.WriteLine(e.Message);
                throw;
            }
            return ret;
        }
        //*----------------------------------------------------------*//
        public static void CommitToDataBase(string connectionString, DataSet ds, string sql)
        {
            try
            {
                if (!ds.HasChanges()) { return; }
                using (OleDbConnection conn = new OleDbConnection())
                {
                    conn.ConnectionString = connectionString;
                    conn.Open();
                    using (OleDbDataAdapter da = new OleDbDataAdapter(sql, conn))
                    {
                        OleDbCommandBuilder b = new OleDbCommandBuilder(da);
                        da.Update(ds.Tables[0]);
                        ds.AcceptChanges();
                    }
                }
            }
            catch (Exception) { throw; }
        }
        //*----------------------------------------------------------*//
        public static DataSet GetDataSet(string connectionString, string sql)
        {
            DataSet ds = new DataSet();
            try
            {
                using (OleDbConnection conn = new OleDbConnection())
                {
                    conn.ConnectionString = connectionString;
                    conn.Open();
                    using (OleDbDataAdapter da = new OleDbDataAdapter(sql, conn))
                    {
                        da.Fill(ds);
                    }
                }
            }
            catch (Exception) { throw; }
            return ds;
        }        
        //*----------------------------------------------------------*//
        private void InsertNewFolder(TreeNode node)
        {
         DataRow row = null;
         DataRow ParentRow = null;
         DataTable dt = null;
         int newindex = 0;
         try
         {
             ParentRow = (DataRow)node.Tag; 
             if (ParentRow == null) { return; }
             newindex = int.Parse(ParentRow["SortOrder"].ToString()) + 1;
             dt = ParentRow.Table;
             row = dt.NewRow();
             row["ModelID"] = int.Parse(ParentRow["ModelID"].ToString());
			 row["NodeID"] = Guid.NewGuid().ToString();
			 row["ParentNodeID"] = ParentRow[dt.PrimaryKey[0].ColumnName].ToString();
             row["Description"] = "New Node";
			 row["ImageIndex"] = 1;
			 row["SelectedImageIndex"] = 2;
             row["SortOrder"] = newindex;
             row["Data"] = txtbNotes.Text;
             dt.Rows.Add(row);
             TreeNode newNode = GetTreeNodeFromDataRow(row, "Description");
             node.Nodes.Add(newNode);
             tvNotes.SelectedNode = newNode; 
         }
         catch (Exception) { throw; }
        }
        //*----------------------------------------------------------*//
        private void tvSampleRightClickInsFolder(object sender, System.EventArgs e)
        {
            Hourglass(true);
            try
            {
                TreeNode node = tvNotes.SelectedNode;
                if ((node == null) || (node.ImageIndex == 3)) { return; }
                InsertNewFolder(node);
            }
            catch (Exception err) { MessageBox.Show(err.Message); }
            finally { Hourglass(false); }
        }
        //*----------------------------------------------------------*//
        public static void LoadFromDataSet(TreeView tv, DataSet ds, string textColumnName)
        {
            TreeNode node;
            DataRow row;
            try
            {
                tv.Nodes.Clear();
                if (ds.Tables.Count < 1) { return; }
                if (ds.Tables[0].Rows.Count < 1) { return; }
                string fkcolumnname = FindForeignKeyColumnName(ds.Tables[0]);
                row = ds.Tables[0].Rows[0];
                tv.BeginUpdate();
                node = GetTreeNodeFromDataRow(row, textColumnName);
                tv.Nodes.Add(node);
                AddNodeFromDataRow(node, row, textColumnName, FindForeignKeyRelationName(row.Table));
            }
            catch (Exception) { throw; }
            finally
            {
                tv.EndUpdate();
                ds.AcceptChanges();
            }
        }
        //*----------------------------------------------------------*//
        public static void AddNodeFromDataRow(TreeNode parentNode, DataRow row, string textColumnName, string dataRelationName)
        {
            try
            {
                foreach (DataRow childrow in row.GetChildRows(dataRelationName))
                {
                    parentNode.Nodes.Add(GetTreeNodeFromDataRow(childrow, textColumnName));
                    AddNodeFromDataRow(parentNode.LastNode, childrow, textColumnName, dataRelationName);
                }
            }
            catch (Exception) { throw; }
        }
        //*----------------------------------------------------------*//
        public static TreeNode GetTreeNodeFromDataRow(DataRow row, string textColumnName)
        {
            TreeNode child = null;
            string imageidx = "";
            string selimageidx = "";
            try
            {
                if (row.Table.Columns.Contains(ImageIndexColumnName))
                {
                    imageidx = row[ImageIndexColumnName].ToString();
                }
                if (row.Table.Columns.Contains(SelectedImageIndexColumnName))
                {
                    selimageidx = row[SelectedImageIndexColumnName].ToString();
                }
                child = new TreeNode();
                child.Text = row[textColumnName].ToString().Trim();
                if (imageidx.Length > 0)
                {
                    child.ImageIndex = Convert.ToInt32(imageidx);
                }
                if (selimageidx.Length > 0)
                {
                    child.SelectedImageIndex = Convert.ToInt32(selimageidx);
                }
                child.Tag = row;
            }
            catch (Exception) { throw; }
            return child;
        }
        //*----------------------------------------------------------*//
        public static string FindForeignKeyColumnName(DataTable dt)
        {
            string Ret = "";
            try
            {
                DataSet ds = dt.DataSet;
                DataRelation rel = ds.Relations[0];
                Ret = rel.ChildColumns[0].ColumnName;
            }
            catch (Exception) { throw; }
            return Ret;
        }
        //*----------------------------------------------------------*//
        public static string FindForeignKeyRelationName(DataTable dt)
        {
            string Ret = "";
            try
            {
                DataSet ds = dt.DataSet;
                DataRelation rel = ds.Relations[0];
                Ret = rel.RelationName;
            }
            catch (Exception) { throw; }
            return Ret;
        }
        //*----------------------------------------------------------*//
	}
}

Open in new window

0
Comment
Question by:peterkiers
  • 5
  • 4
10 Comments
 
LVL 8

Accepted Solution

by:
crysallus earned 450 total points
ID: 35145834
I've done this before by assigning to the TreeView's TreeViewNodeSorter property a class that implements IComparer, which defines the basis for sorting in a Compare method. To just do basic alphabetic sorting on the Text property of the TreeNode, this should work:

public class TreeViewSorter : IComparer
{
	public int Compare(object x, object y)
	{
		var n1 = x as TreeNode;
		var n2 = y as TreeNode;

		if (n1 == null || n2 == null)
			return 0;

		return string.Compare(n1.Text, n2.Text);
	}
}

Open in new window

Then add this line to assign it to the treeview, probably in the constructor for your form, or perhaps your form's load event.

tvNotes.TreeViewNodeSorter = new TreeViewSorter();

Open in new window

You may want to change the name to something less generic, but that at least gives you the idea.

You can also implement more complicated sorting criteria, just return -1 if x comes before y, 1 if x comes after y.
0
 

Assisted Solution

by:satishmp
satishmp earned 50 total points
ID: 35145881
HI ,

the easiest way to sort a TreeView is to:

* add the nodes to an ArrayList
* sort the ArrayList with an IComparer
* remove the nodes from the TreeView and add them back from the
ArrayList.

e.g. in a sub-class of TreeView:

public void Sort(IComparer comparer) {

ArrayList list = new ArrayList(this.Nodes.Count);
foreach (TreeNode childNode in this.Nodes) {
list.Add(childNode);
}
list.Sort(comparer);

this.BeginUpdate();
this.Nodes.Clear();
foreach (TreeNode childNode in list) {
this.Nodes.Add(childNode);
}
this.EndUpdate();
}

Obviously, this can be adapted to deal with the child-nodes of
individual nodes. Just pass a node to the method above, and replace
this.Nodes with node.Nodes.

You can also do it with API calls, but it's messy and as far as I can
tell, it's not much quicker.

Satish
0
 
LVL 1

Author Comment

by:peterkiers
ID: 35145994
crysallus, I want to ty your solution. I just begun with C# so I am not that good.
Is it possible to implement it without making use of a class.

P.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 35146012
       public static void LoadFromDataSet(TreeView tv, DataSet ds, string textColumnName)
        {
            TreeNode node;
            DataRow row;
            try
            {
                tv.Nodes.Clear();
                if (ds.Tables.Count < 1) { return; }
                if (ds.Tables[0].Rows.Count < 1) { return; }
                string fkcolumnname = FindForeignKeyColumnName(ds.Tables[0]);
                row = ds.Tables[0].Rows[0];
                tv.BeginUpdate();
                tv.TreeViewNodeSorter;          <================================
                node = GetTreeNodeFromDataRow(row, textColumnName);
                tv.Nodes.Add(node);
                AddNodeFromDataRow(node, row, textColumnName, FindForeignKeyRelationName(row.Table));
            }
            catch (Exception) { throw; }
            finally
            {
                tv.EndUpdate();
                ds.AcceptChanges();
            }
        }

I get error:Only assignment, call, increment, decrement, and new object expressions can be used as a statement      

P.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 35146052
I have done this but I get errors:
        //*----------------------------------------------------------*//
        public class NodeSorter : IComparer
        {
            public int Compare(object x, object y)
            {
                TreeNode tx = x as TreeNode;
                TreeNode ty = y as TreeNode;
                if (tx.Text.Length != ty.Text.Length)
                    return tx.Text.Length - ty.Text.Length;
                return string.Compare(tx.Text, ty.Text);
            }
        }
        //*----------------------------------------------------------*//
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            tvNotes.TreeViewNodeSorter = new NodeSorter();
        }
        //*----------------------------------------------------------*//

1.
Cannot implicitly convert type 'DbTreeView.MainForm.NodeSorter' to 'System.Collections.IComparer'. An explicit conversion exists (are you missing a cast?)      

2.
Using the generic type 'System.Collections.Generic.IComparer<T>' requires 1 type arguments      

Peter
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 8

Expert Comment

by:crysallus
ID: 35146107
sounds like you are missing

using System.Collections;

Open in new window

BTW, setting the TreeViewNodeSorter property doesn't actually do the sorting, it just defines how it should be sorted when the time comes for it to be sorted. To actually sort it call the Sort() method if it's not doing it for you by default when you want it to.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 35146147
"BTW, setting the TreeViewNodeSorter property doesn't actually do the sorting, it just defines how it should be sorted when the time comes for it to be sorted. To actually sort it call the Sort() method if it's not doing it for you by default when you want it to. "

How can I call the Sort() methode ???

Peter
0
 
LVL 8

Expert Comment

by:crysallus
ID: 35146325
tvNotes.Sort();

no arguments required.
0
 
LVL 8

Expert Comment

by:crysallus
ID: 35146398
The thing is when I used this before, I'm pretty sure the sorting was automatically done when I updated the TreeView's nodes, so I didn't have to manually call Sort() - which is why I didn't mention it earlier, because I didn't need to do it. I only mentioned it in case you wanted to manually force a sort in a non-default way, such as the click event which you posted earlier.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 35146431
Thanks for the info.

Greetings, Peter Kiers
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now