none
How can I fake a grid in .NET with the scrolling speed of Excel?

    Question

  • Firstly, this is a legacy system and I am not responsible for it's existence, just its maintenance and enhancement.

    I have a large VB.NET app that generates a grid using label controls. The reason for using label controls rather than a datagrid is because the cells are of varying width both within a row and across rows, something Excel cannot directly do (yes, I could mess around with merge cells etc). On screen you see 40 'rows' (subject to screen res) and about 13 'columns', but could be far more, there could 1000+ data rows, even 10,000+ to display/scroll through.

    Label controls are created as needed and recycled, when the user scrolls the controls are jiggled into their new positions, unused controls are hidden. Right-click menus and drag drop are used. The controls are hosted within a panel control which is in a tab page, there could be several such tab pages at once.

    Scrolling is painfully slow, it can take 2-3s on a 8 core Xeon with fairly modern NVidia graphics. Using the VS 2010 profiler nearly all of the time in scrolling is spent setting the Left and Width property of the controls. As a test I compared a VB.NET app randomly moving 1000 labels to a C API app, the API app was twice as fast. This shows the bottleneck is not an inherent problem in Windows but .NET. I am not allowed to use the API however.

    So far I have disabled redrawing using this http://dotnet.mvps.org/dotnet/faqs/?...rawing&lang=en and suspended the layout of the parent panel (which seems fairly ineffective).

    If I were to go back to the drawing board, how could I generate the required layout and support right-click menus and drag drop and instant scrolling?

    .NET apps cannot create more than 10,000 controls so creating everything up front is not a realistic option, tried that too.

    Attached a censored screenshot showing the layout, clearer than my description.Name:  example.png
Views: 1
Size:  10.0 KB

    TIA
    Tuesday, January 08, 2013 4:48 PM

Answers

  • Ohh boy... looks like a scheduler or something similar...!

    Ok so here's the scoop:

    It sounds like the control was originally written about as efficiently as possible using labels.  If you shrink your window so that it is like 640x480 it probably scrolls at what you might call acceptable (if not good), but at larger resolutions it becomes painful to scroll.  And since your video card has absolutely no bearing (GDI+ uses the CPU and is not accelerated) there's little you can do to make it run faster.

    The answer here is to get rid of the controls entirely.  Draw the grid yourself by overriding the OnPaint method of a custom Control class.  You really just need to calculate and draw a bunch of rectangles and draw in some text.  Judging by the screen shot there is no reason at all why you wouldn't be able to make that grid scroll smoothly, assuming that there is not some huge amount of processing going on in the background whenever the view changes.

    Assuming that most of the data being displayed already exists, and there are only nominal calculations to perform before displaying the data (if any at all), then this should be fairly easy to do with just a bunch of calls to Graphics methods.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Tuesday, January 08, 2013 8:57 PM
    Moderator

All replies

  • Using the VS 2010 profiler nearly all of the time in scrolling is spent setting the Left and Width property of the controls. As a test I compared a VB.NET app randomly moving 1000 labels to a C API app, the API app was twice as fast. This shows the bottleneck is not an inherent problem in Windows but .NET. I am not allowed to use the API however.

    Is there anything about the code which sets the Left and Width properties which could be slowing it down, e.g. retrieving the data from a databse? Or a call to Application.DoEvents?

    Edit: Also, have you tried using a DataGridView with virtual mode?

    --
    Andrew

    Tuesday, January 08, 2013 5:20 PM
  • Mark,

    I'll toss this out as a "maybe this will work" idea.

    Instead of all that, go to a better grid control like this one from Dev Express. It supports Cell Merging.

    It's a thought. :)


    Please call me Frank :)

    Tuesday, January 08, 2013 6:33 PM
  • Frank,

    I agree with that idea, but the OP has already dismissed that due to bad experience with something else at another time: stackoverflow.com/questions/14217600/how-can-i-fake-a-grid-in-net-with-the-scrolling-speed-of-excel.

    --
    Andrew

    Tuesday, January 08, 2013 7:47 PM
  • Ohh boy... looks like a scheduler or something similar...!

    Ok so here's the scoop:

    It sounds like the control was originally written about as efficiently as possible using labels.  If you shrink your window so that it is like 640x480 it probably scrolls at what you might call acceptable (if not good), but at larger resolutions it becomes painful to scroll.  And since your video card has absolutely no bearing (GDI+ uses the CPU and is not accelerated) there's little you can do to make it run faster.

    The answer here is to get rid of the controls entirely.  Draw the grid yourself by overriding the OnPaint method of a custom Control class.  You really just need to calculate and draw a bunch of rectangles and draw in some text.  Judging by the screen shot there is no reason at all why you wouldn't be able to make that grid scroll smoothly, assuming that there is not some huge amount of processing going on in the background whenever the view changes.

    Assuming that most of the data being displayed already exists, and there are only nominal calculations to perform before displaying the data (if any at all), then this should be fairly easy to do with just a bunch of calls to Graphics methods.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Tuesday, January 08, 2013 8:57 PM
    Moderator
  • I have posted this question in a few forums to garner as much discussion as possible before a meeting with the TD tomorrow.

    I have tried a drawn solution before but I had issues with replicating the drag/drop functionality because there is no control to drag and no control to drop onto. I want to disturb as little code as possible as all the drag over/on code is control based. If I were to implement drag drop entirely using 'drawings' I would need a shim between the existing code and the new code. Not really an issue, but it's still more new code.

    Otherwise your proposed solution sounds pretty ideal and your assumptions are pretty much correct. All the data is loaded up front, the only calculations when scrolling are the co-ordinates and width and a other things to do with the cells appearance.

    I've also had some suggestions to do something with a datagridview. 

    Tuesday, January 08, 2013 11:19 PM
  • BTW, this is a VB6 port (before my time I hasten to add). From what I understand from other old forum posts control movement was zippy in VB6 but slowed down dramatically in .NET.
    Tuesday, January 08, 2013 11:34 PM
  • Using the VS 2010 profiler nearly all of the time in scrolling is spent setting the Left and Width property of the controls. As a test I compared a VB.NET app randomly moving 1000 labels to a C API app, the API app was twice as fast. This shows the bottleneck is not an inherent problem in Windows but .NET. I am not allowed to use the API however.

    Is there anything about the code which sets the Left and Width properties which could be slowing it down, e.g. retrieving the data from a databse? Or a call to Application.DoEvents?

    Edit: Also, have you tried using a DataGridView with virtual mode?

    --
    Andrew

    I set them to straight integers that are calculated using locally available data. I know nothing about DataGridView but it has cropped in several responses I've had.
    Tuesday, January 08, 2013 11:37 PM
  • Actually you can have "psuedo controls" to drag and drop.  You might have an object that defines a block in the chart.  This logical object would contain the data related to the block as well as the information describing the appearance (location, size, color etc).  By keeping a list of these blocks you can test to see which block's bounds contain the mouse location.  At this point it is trivial to show a context menu, and drag and drop should not be too much more difficult given that you have an existing implementation to work with.  Instead of setting a label as the data object for the drag and drop you would set your custom block object as the data object.

    Obviously I'm making some assumptions about how the program is built so I realize that it might not be as easy as that.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, January 08, 2013 11:55 PM
    Moderator