Solved

How to sort a treeview alfabeticly

Posted on 2011-03-16
10
740 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
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

914 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

21 Experts available now in Live!

Get 1:1 Help Now