Solved

How to sort a treeview alfabeticly

Posted on 2011-03-16
10
748 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Major Incident Management Communications

Major incidents and IT service outages cost companies millions. Often the solution to minimizing damage is automated communication. Find out more in our Major Incident Management Communications infographic.

 
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
 
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Nested forach loop to linq 3 45
Web page design problem 3 42
Building an object from several other objects 4 39
Which is best Image Resizing Web service 11 42
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…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

752 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