Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. DataGridView line index cells

DataGridView line index cells

Scheduled Pinned Locked Moved C#
databasequestion
8 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    eyalbi007
    wrote on last edited by
    #1

    Hi, I'm trying to add line index cell to my DataGridView by iterating over the rows. However, when the list has many rows (hundreds), this loop takes very long time due to CPU consuming. The "heavy" part is converting the "int" to "String". The code:

    for (int iRowIter = 0; iRowIter < this.Rows.Count; iRowIter++)
    this.Rows[iRowIter].Cells[0].Value = iRowIter + 1;

    Any suggestions? Thanks!

    N D 2 Replies Last reply
    0
    • E eyalbi007

      Hi, I'm trying to add line index cell to my DataGridView by iterating over the rows. However, when the list has many rows (hundreds), this loop takes very long time due to CPU consuming. The "heavy" part is converting the "int" to "String". The code:

      for (int iRowIter = 0; iRowIter < this.Rows.Count; iRowIter++)
      this.Rows[iRowIter].Cells[0].Value = iRowIter + 1;

      Any suggestions? Thanks!

      N Offline
      N Offline
      N a v a n e e t h
      wrote on last edited by
      #2

      eyalbi007 wrote:

      for (int iRowIter = 0; iRowIter < this.Rows.Count; iRowIter++) this.Rows[iRowIter].Cells[0].Value = iRowIter + 1;

      IMO, Iterating and putting line number will not be the best option. Try handling RowPostPaint[^] or RowPrePaint event. You will get index of the current row. Using that get the row object and add line number (RowIndex + 1). This will avoid unnecessary iterations on the gridview. :)

      Best wishes, Navaneeth

      E 1 Reply Last reply
      0
      • E eyalbi007

        Hi, I'm trying to add line index cell to my DataGridView by iterating over the rows. However, when the list has many rows (hundreds), this loop takes very long time due to CPU consuming. The "heavy" part is converting the "int" to "String". The code:

        for (int iRowIter = 0; iRowIter < this.Rows.Count; iRowIter++)
        this.Rows[iRowIter].Cells[0].Value = iRowIter + 1;

        Any suggestions? Thanks!

        D Offline
        D Offline
        dojohansen
        wrote on last edited by
        #3

        First of all, I don't actually see any code here that converts an int to a string. Second, I doubt your analysis is correct - doing this over a few hundred rows should *not* take long.

        E 1 Reply Last reply
        0
        • D dojohansen

          First of all, I don't actually see any code here that converts an int to a string. Second, I doubt your analysis is correct - doing this over a few hundred rows should *not* take long.

          E Offline
          E Offline
          eyalbi007
          wrote on last edited by
          #4

          1. Since the relevant DataGridView cells display Strings, there is an automatic conversion from (iRowIter + 1), which is int, to Cells[0].Value which is String Object in this case. It's the same as

          Cells[0].Value = Convert.ToString(iRowIter + 1)

          2. My analysis is correct. I tried the following code:

          Cells[0].Value = "1"

          and it worked amazingly fast.

          D 1 Reply Last reply
          0
          • N N a v a n e e t h

            eyalbi007 wrote:

            for (int iRowIter = 0; iRowIter < this.Rows.Count; iRowIter++) this.Rows[iRowIter].Cells[0].Value = iRowIter + 1;

            IMO, Iterating and putting line number will not be the best option. Try handling RowPostPaint[^] or RowPrePaint event. You will get index of the current row. Using that get the row object and add line number (RowIndex + 1). This will avoid unnecessary iterations on the gridview. :)

            Best wishes, Navaneeth

            E Offline
            E Offline
            eyalbi007
            wrote on last edited by
            #5

            Hi, First of all, thanks. Your solution saves the iterating part. However, the problem with using these events is that it's called every time the row is painted (for example, when scrolling). This slows down the response time since every time a row becomes visible (due to scrolling) the value of the index cell is set all over again. Even if I add "if" statement (in order to update the index cell only when required), scrolling after sorting becomes very slow since the index cell of the hidden rows wasn't updated yet. Any suggestions? Eyal.

            1 Reply Last reply
            0
            • E eyalbi007

              1. Since the relevant DataGridView cells display Strings, there is an automatic conversion from (iRowIter + 1), which is int, to Cells[0].Value which is String Object in this case. It's the same as

              Cells[0].Value = Convert.ToString(iRowIter + 1)

              2. My analysis is correct. I tried the following code:

              Cells[0].Value = "1"

              and it worked amazingly fast.

              D Offline
              D Offline
              dojohansen
              wrote on last edited by
              #6

              First of all, C# doesn't allow implicit conversion from int to string, as demonstrated by this snippet:

              void foo()
              {
              string s;
              s = 5;
              }

              Cannot implicitly convert type 'int' to 'string'. So that's not what's going on and your "equivalent statement" isn't equivalent at all. Second, DataGridViewCell.Value is not of type string - it's of type object. That means that if you assign a value type to it (such as int) there is a boxing operation, but a few hundred boxing operations (which is what you get with a few hundred rows) does NOT take long. Try it for yourself:

              // Making this a public instance member guarantees the compiler cannot optimize away the operations.
              public object obj;

              string test()
              {
              int count = 10000;
              var w = Stopwatch.StartNew();
              for (int i = 0; i < count; i++)
              {
              obj = i;
              }
              w.Stop();
              return string.Format("{0} boxing operations took {1}.", count, w.Elapsed);
              }

              Show it in a messagebox or just set a breakpoint (after w.Stop(), obviously!) and see what you get. On my lameass workstation 10,000 boxing operations took 0.0001546 seconds. In a debug build. With the debugger attached. In short, the boxing is not going to make any noticeable difference. Something else is clearly going on here. That said, if assigning the string literal was so fast, why don't you try

              Cells[0].Value = (iRowIter + 1).ToString();

              instead? Calling ToString() on an int is not expensive either, so if there really is some oddity in the DataGridView that makes it freak out if it has to work with ints this should work around it. I find it difficult to believe such a major flaw in the component would have gone unnoticed though.

              E 1 Reply Last reply
              0
              • D dojohansen

                First of all, C# doesn't allow implicit conversion from int to string, as demonstrated by this snippet:

                void foo()
                {
                string s;
                s = 5;
                }

                Cannot implicitly convert type 'int' to 'string'. So that's not what's going on and your "equivalent statement" isn't equivalent at all. Second, DataGridViewCell.Value is not of type string - it's of type object. That means that if you assign a value type to it (such as int) there is a boxing operation, but a few hundred boxing operations (which is what you get with a few hundred rows) does NOT take long. Try it for yourself:

                // Making this a public instance member guarantees the compiler cannot optimize away the operations.
                public object obj;

                string test()
                {
                int count = 10000;
                var w = Stopwatch.StartNew();
                for (int i = 0; i < count; i++)
                {
                obj = i;
                }
                w.Stop();
                return string.Format("{0} boxing operations took {1}.", count, w.Elapsed);
                }

                Show it in a messagebox or just set a breakpoint (after w.Stop(), obviously!) and see what you get. On my lameass workstation 10,000 boxing operations took 0.0001546 seconds. In a debug build. With the debugger attached. In short, the boxing is not going to make any noticeable difference. Something else is clearly going on here. That said, if assigning the string literal was so fast, why don't you try

                Cells[0].Value = (iRowIter + 1).ToString();

                instead? Calling ToString() on an int is not expensive either, so if there really is some oddity in the DataGridView that makes it freak out if it has to work with ints this should work around it. I find it difficult to believe such a major flaw in the component would have gone unnoticed though.

                E Offline
                E Offline
                eyalbi007
                wrote on last edited by
                #7

                Thanks a lot, you are totally right! I found the problem: The column's AutoSizeMode property was set to DataGridViewAutoSizeColumnMode.AllCells, which dragged heavy calculations every time one of the column's cells value was changed. I changed it to DataGridViewAutoSizeColumnMode.None and now everything works smooth. In order to have the auto-size functionality, I've set the column's Resizable property to DataGridViewTriState.False, and added calls of AutoResizeColumn(ColumnIndex) where it's needed. Again, thanks a lot. Eyal.

                D 1 Reply Last reply
                0
                • E eyalbi007

                  Thanks a lot, you are totally right! I found the problem: The column's AutoSizeMode property was set to DataGridViewAutoSizeColumnMode.AllCells, which dragged heavy calculations every time one of the column's cells value was changed. I changed it to DataGridViewAutoSizeColumnMode.None and now everything works smooth. In order to have the auto-size functionality, I've set the column's Resizable property to DataGridViewTriState.False, and added calls of AutoResizeColumn(ColumnIndex) where it's needed. Again, thanks a lot. Eyal.

                  D Offline
                  D Offline
                  dojohansen
                  wrote on last edited by
                  #8

                  You're welcome! And thanks for posting the explanation. I knew it wasn't conversion from int to string that took the time, but I had no idea what it really was and your findings may be of use to someone else (including myself) some day. However, I think the way we're intended to avoid this is to call BeginEdit() and EndEdit() - this pattern is used with many controls to suppress expensive side-effects until EndEdit is called. For some reason I just didn't think about that.

                  DataGridView v;

                  v.BeginEdit();
                  try
                  {
                  // .. do a lot of editing
                  }
                  finally
                  {
                  v.EndEdit();
                  }

                  (The BeginEdit is not part of the try block because we should only call EndEdit if BeginEdit has actually succeeded - though this is of course academic if the call to BeginEdit() always succeeds.)

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups