none
How to sort Form.Controls collection base on my criteria ? RRS feed

  • Question

  • Hi

    i want to sort my form controls first, base on it's y location asc, then it's x location desc ?

    thanks in advance


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 11:58 AM

Answers

  • i think this code works fine, but sorting base on 'X' location must be Desc (not asc). how can i change this code to accomplish this ?
    Hamed, Rudy's reply need a little modification; you hardly mark as answer a reply ;)
      public class PointComparer : IComparer<Control>
      {
        #region IComparer<Control> Members
        public int Compare(Control x, Control y)
        {
          Int64 xp = ((Int64)x.Location.Y << 32) + (Int32.MaxValue - x.Location.X);
          Int64 yp = ((Int64)y.Location.Y << 32) + (Int32.MaxValue - y.Location.X);
          return xp.CompareTo(yp);
        }
        #endregion
      }
    
    

    LEARN HOW TO USE WINDOWS API DURING A QUICK, SIMPLE AND PRACTICAL HOW TO:
    How To: Changing TextBox blinking caret using Windows API
    • Marked as answer by Rudedog2 Saturday, February 19, 2011 9:55 PM
    • Unmarked as answer by Rudedog2 Saturday, February 19, 2011 10:05 PM
    • Marked as answer by Rudedog2 Saturday, February 19, 2011 10:06 PM
    Saturday, February 19, 2011 5:04 PM
  •  

                decimal GenerateComparer(Point location)

                {

                    decimal yloc = (decimal)location.Y;

                    decimal xloc = (decimal)location.X;

                    return yloc + ((1000m - xloc) / 1000m);  // modification here

                }

     


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 10:04 PM

All replies

  • A sample implementation would be as shown below:

          foreach (Control c in this.Controls)
          {
            int yAxis = c.Location.Y;
            int xAxis = c.Location.X;
            // Store this values somewhere and sort it accordingly
          }
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.
    Friday, February 18, 2011 12:09 PM
  • A sample implementation would be as shown below:

       foreach (Control c in this.Controls)
       {
        int yAxis = c.Location.Y;
        int xAxis = c.Location.X;
        // Store this values somewhere and sort it accordingly
       }
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.

    Thanks

    but i want to sort my controls collection base on my criterias.


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 12:53 PM
  • how about something like this? note here that i am storing data in datatable and querying it.

          DataTable dtControls = new DataTable();
          dtControls.Columns.Add("ControlName",typeof(string));
          dtControls.Columns.Add("X",typeof(int));
          dtControls.Columns.Add("Y",typeof(int));
          foreach (Control c in this.Controls)
          {
            dtControls.Rows.Add(c.Name, c.Location.X, c.Location.Y);
          }
          // Sorts controls in Y axis ascending
          DataRow[] xSort = dtControls.Select(null, "Y ASC");
          // Sorts controls in X axis descending
          DataRow[] ySort = dtControls.Select(null, "X DESC");
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.
    Friday, February 18, 2011 2:46 PM
  • how about something like this? note here that i am storing data in datatable and querying it.

       DataTable dtControls = new DataTable();
       dtControls.Columns.Add("ControlName",typeof(string));
       dtControls.Columns.Add("X",typeof(int));
       dtControls.Columns.Add("Y",typeof(int));
       foreach (Control c in this.Controls)
       {
        dtControls.Rows.Add(c.Name, c.Location.X, c.Location.Y);
       }
       // Sorts controls in Y axis ascending
       DataRow[] xSort = dtControls.Select(null, "Y ASC");
       // Sorts controls in X axis descending
       DataRow[] ySort = dtControls.Select(null, "X DESC");
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.

    Thanks Balaji

    your post was helpful for me. many thanks.

    any way, i found a way to accomplish this via List<T>.Sort method as follow :

    List<Control> controls = new List<Control>();
          foreach (Control c in this.Controls)
            controls.Add(c);
          controls.Sort(delegate(Control c1, Control c2)
          {
            return Comparer<int>.Default.Compare(c1.Location.Y, c2.Location.Y);
          });
          controls.Sort(delegate(Control c1, Control c2)
          {
            return Comparer<int>.Default.Compare(c2.Location.X, c1.Location.X);
          });
    
    

    but does not give me a correct result as i expected!

    can u test this code ?

    thanks in advance


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 8:18 PM
  • Create a custom collection class---inherited from List<t>---that sorts items as they are added.

    It might prove to be useful to create a custom item class that wraps Control.

     http://msdn.microsoft.com/en-us/library/234b841s.aspx


     

    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Friday, February 18, 2011 9:16 PM
  • Create a custom collection class---inherited from List<t>---that sorts items as they are added.

    It might prove to be useful to create a custom item class that wraps Control.

     


     

    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Hi

    Can u give me an example which how to accomplish this ?

    thanks


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 9:23 PM
  • I did. 

    You deleted the link when you quoted my reply.  The IComparer interface specifies a method that compares just 2 items.  The rest is taken care of by the internals of the List<>Sort method overload that specifies an IComparer instance to be used to perform the Sort.


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Friday, February 18, 2011 9:46 PM
  • I did. 

    You deleted the link when you quoted my reply.  The IComparer interface specifies a method that compares just 2 items.  The rest is taken care of by the internals of the List<>Sort method overload that specifies an IComparer instance to be used to perform the Sort.


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Sorry

    but i did not got your mean!

    can u give me an example or more description ?

    thanks


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 9:56 PM
  •  http://msdn.microsoft.com/en-us/library/234b841s.aspx



    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Friday, February 18, 2011 10:00 PM
  • I saw your link, but as you told, this example compare just 2 strings, wheras i don't know should i do this or change the compairson algorythm to compare more than 2 objects. here is my problem
    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Friday, February 18, 2011 10:06 PM
  • Dude.  I already told you that all the method needs to do is compare just 2 items.  That means compare just two controls according to any criteria you define.

    Yes, the example compares two strings.  You need to create a method that compares only 2 controls.  Compare the Y values, and then compare the X values if the Y values are the same.  Done.  You do not need anything as fancy as what you posted earlier. 

    Here's the non-generic overload of List.Sort.  It is identical, just not as complicated looking.

    http://msdn.microsoft.com/en-us/library/0e743hdt.aspx

    All the method needs to do is return a positive number or a negative number depending upon which of the 2 input parameters is "greater".  Return a zero if they are "equal".


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Friday, February 18, 2011 10:16 PM
  • create a class to store your data:

      public class CustomControls
      {
        private string controlName;
    
        public string ControlName
        {
          get { return controlName; }
          set { controlName = value; }
        }
        private int xAxis;
    
        public int XAxis
        {
          get { return xAxis; }
          set { xAxis = value; }
        }
        private int yAxis;
    
        public int YAxis
        {
          get { return yAxis; }
          set { yAxis = value; }
        }
      }
    

    and the in the form code the implementation logic can be this way:

          List<CustomControls> customCtrls = new List<CustomControls>();
          foreach (Control c in this.Controls)
          {
            CustomControls ctrl = new CustomControls();
            ctrl.ControlName = c.Name;
            ctrl.XAxis = c.Location.X;
            ctrl.YAxis = c.Location.Y;
            customCtrls.Add(ctrl);
          }
    
          // Sorting in Ascending (Y Axis)
          customCtrls.Sort(delegate(CustomControls c1, CustomControls c2)
          { return c1.YAxis.CompareTo(c2.YAxis); });
          // Sorting in Descending (X Axis)
          customCtrls.Sort(delegate(CustomControls c1, CustomControls c2)
          { return c1.XAxis.CompareTo(c2.XAxis); });
          customCtrls.Reverse();
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.
    Friday, February 18, 2011 10:22 PM
  • This custom Comparer class compares just the Location.Y values.  You would use this with the method at the link in my previous post.

    class MyControls : List<Control>

        {

            ControlLocationComparer comparer = new ControlLocationComparer();

            public new void Add(Control item)

            {

                this.Add(item);

                this.Sort(this.comparer);

            }

     

            class ControlLocationComparer : IComparer<Control>

            {

     

                #region IComparer<Control> Members

     

                public int Compare(Control x, Control y)

                {

     

                    int result = 0;

                    Control ctrl_x = x as Control;

                    Control ctrl_y = y as Control;

                    if ( ctrl_x == null || ctrl_y == null )

                    {

                        throw new NullReferenceException("Compared item was null.");

                    }

                    if ( ctrl_x.Location.Y > ctrl_y.Location.Y )

                    {

                        result = 1;

                    }

                    if ( ctrl_x.Location.Y < ctrl_y.Location.Y )

                    {

                        result = -1;

                    }

                    return result;

                }

     

                #endregion

            }

        }

     


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Friday, February 18, 2011 10:37 PM
  • create a class to store your data:

     public class CustomControls
     {
      private string controlName;
    
      public string ControlName
      {
       get { return controlName; }
       set { controlName = value; }
      }
      private int xAxis;
    
      public int XAxis
      {
       get { return xAxis; }
       set { xAxis = value; }
      }
      private int yAxis;
    
      public int YAxis
      {
       get { return yAxis; }
       set { yAxis = value; }
      }
     }
    

    and the in the form code the implementation logic can be this way:

       List<CustomControls> customCtrls = new List<CustomControls>();
       foreach (Control c in this.Controls)
       {
        CustomControls ctrl = new CustomControls();
        ctrl.ControlName = c.Name;
        ctrl.XAxis = c.Location.X;
        ctrl.YAxis = c.Location.Y;
        customCtrls.Add(ctrl);
       }
    
       // Sorting in Ascending (Y Axis)
       customCtrls.Sort(delegate(CustomControls c1, CustomControls c2)
       { return c1.YAxis.CompareTo(c2.YAxis); });
       // Sorting in Descending (X Axis)
       customCtrls.Sort(delegate(CustomControls c1, CustomControls c2)
       { return c1.XAxis.CompareTo(c2.XAxis); });
       customCtrls.Reverse();
    

    Balaji Baskar
    http://codesupport.wordpress.com
    Click on "Vote As Helpful" and "Mark As Answer" if this has helped you.

    Thanks Balaji

    but this code does not return my expected result.


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Saturday, February 19, 2011 6:37 AM
  • Hamed,

    We don't understand what "your expected result" actually is.  You are looking for a concise solution by provided only vague descriptions of whatever it is that you are after.  You have declared the previous suggestion as wrong.  Yet, you fail to describe exactly "what" is wrong, and what "right" should actually be.

    No one understands your objective, Hamed.  Telling people over and over, "That's not my expected result," is almost laughable.  You paint a picture of yourself that says you want others to do your work while you stand back and watch.  It is almost laughbable, but truthfully it is pretty sad.  You actually posted code and asked someone to test it for you.  Now that was funny.

    I posted code that will only sort by the Location.Y value for a reason.  I don't know how the Location.X values should be sorted.  Too many unkowns to even try.   So, I posted code to meet you halfway.  Though my code snippet only sorts the "Y" values, it could very easily be extended to sort the "X" values.  Try it.  Does it sort the "Y" values?

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    • Edited by Rudedog2 Saturday, February 19, 2011 3:38 PM
    Saturday, February 19, 2011 1:43 PM
  • I wrote a new class to use as a Comparer object in my previous post.

     

            public decimal MaximumX;

            public decimal MaximumY;

            class PointComparer : IComparer<Control>

            {

                #region IComparer<Control> Members

     

                public int Compare(Control x, Control y)

                {

                    decimal xp = GenerateComparer(x.Location);

                    decimal yp = GenerateComparer(y.Location);

                    return Decimal.Compare(xp, yp);

                }

     

                decimal GenerateComparer(Point location)

                {

                    decimal yloc = (decimal)location.Y;

                    decimal xloc = (decimal)location.X;

                    return yloc + (xloc / 1000m);

                }

     

                #endregion

            }

     

    The variables declared in the GenerateComparer method might need some adjusting to compensate ascending or descending sorting.


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 3:35 PM
  • Hamed,

    We don't understand what "your expected result" actually is.  You are looking for a concise solution by provided only vague descriptions of whatever it is that you are after.  You have declared the previous suggestion as wrong.  Yet, you fail to describe exactly "what" is wrong, and what "right" should actually be.

    No one understands your objective, Hamed.  Telling people over and over, "That's not my expected result," is almost laughable.  You paint a picture of yourself that says you want others to do your work while you stand back and watch.  It is almost laughbable, but truthfully it is pretty sad.

    I posted code that will only sort by the Location.Y value for a reason.  I don't know how the Location.X values should be sorted.  Too many unkowns to even try.   So, I posted code to meet you halfway.  Though my code snippet only sorts the "Y" values, it could very easily be extended to sort the "X" values.  Try it.  Does it sort the "Y" values?

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Hi Rudy

    sorry for my less description.

    to understand what i need, please see this form image.

    As you can see, there is a lot of controls on form in various places. i want to sort these controls first by 'Y Asc', then by 'X Desc'. my expected result would be this :

    button2

    txtY

    txtX

    button1

    txtHeight

    txtWidth

    label1

    textBox1

    label2

    textBox2

    listBox1

    label3

    textBox3

    thanks


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Saturday, February 19, 2011 3:46 PM
  • I guess that means you have not tested my code, not even for your own self benefit.
    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 4:03 PM
  • I created a custom collection class---inherited from List<Control>---that sorts the entire collection as new items are added.
    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 4:12 PM
  • I created a custom collection class---inherited from List<Control>---that sorts the entire collection as new items are added.
    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Thanks Rudy

    i've tested your code. i've wrote this :

    public class PointComparer : IComparer<Control>
    {
        #region IComparer<Control> Members
    
        public int Compare(Control x, Control y)
        {
          decimal xp = GenerateComparer(x.Location);
          decimal yp = GenerateComparer(y.Location);
          return Decimal.Compare(xp, yp);
        }
    
        decimal GenerateComparer(Point location)
        {
          decimal yloc = (decimal)location.Y;
          decimal xloc = (decimal)location.X;
          return yloc + (xloc / 1000m);
        }
    
        #endregion
    }
    
    List<Control> controls = new List<Control>();
          foreach (Control c in this.Controls)
            controls.Add(c);
    
          PointComparer comparer = new PointComparer();
          controls.Sort(comparer);
          foreach (Control c in controls)
          {
            listBox1.Items.Add(string.Format("{0}- {1}:{2}", c.Name, c.Location.X, c.Location.Y));
          }
    

    i think this code works fine, but sorting base on 'X' location must be Desc (not asc). how can i change this code to accomplish this ?

    thanks


    http://www.codeproject.com/KB/codegen/DatabaseHelper.aspx
    Saturday, February 19, 2011 4:21 PM
  • i think this code works fine, but sorting base on 'X' location must be Desc (not asc). how can i change this code to accomplish this ?
    Hamed, Rudy's reply need a little modification; you hardly mark as answer a reply ;)
      public class PointComparer : IComparer<Control>
      {
        #region IComparer<Control> Members
        public int Compare(Control x, Control y)
        {
          Int64 xp = ((Int64)x.Location.Y << 32) + (Int32.MaxValue - x.Location.X);
          Int64 yp = ((Int64)y.Location.Y << 32) + (Int32.MaxValue - y.Location.X);
          return xp.CompareTo(yp);
        }
        #endregion
      }
    
    

    LEARN HOW TO USE WINDOWS API DURING A QUICK, SIMPLE AND PRACTICAL HOW TO:
    How To: Changing TextBox blinking caret using Windows API
    • Marked as answer by Rudedog2 Saturday, February 19, 2011 9:55 PM
    • Unmarked as answer by Rudedog2 Saturday, February 19, 2011 10:05 PM
    • Marked as answer by Rudedog2 Saturday, February 19, 2011 10:06 PM
    Saturday, February 19, 2011 5:04 PM
  •  

                decimal GenerateComparer(Point location)

                {

                    decimal yloc = (decimal)location.Y;

                    decimal xloc = (decimal)location.X;

                    return yloc + ((1000m - xloc) / 1000m);  // modification here

                }

     


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 10:04 PM
  • Thanks, Yasser.

    Hamed,

    Yasser's solution does the same thing using Integers, that mine does with decimals.  I figured the decimal example might be easier to understand, but Yasser's solution should be faster.

    I still suggest that you use the custom collection class.  It will guarantee that the collection is always sorted.


    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 19, 2011 10:09 PM