views:

1737

answers:

4

If you put a DataGridView that is 400 pixels high on a panel that's 300 pixels high, so that there's a scroll bar on the panel, then scroll down so that the lower half of the grid is shown, then click on a control outside the panel, then click on a line in the grid, the panel scrolls up to the top and the wrong row in the grid is selected.

It's not just a DataGridView; it happens with any control that's higher than the panel, eg Infragistics UltraWinGrid, Rich Text Box. I raised it as a bug with Infragistics, but they say it's a Microsoft issue.

I've tried using all the relevant events for the controls, but the Panel scroll happens before the events fire.

Any suggestions?

+1  A: 

I understand your pain, this has gotten me more than once.

If your DataGridView is the only thing in the panel, just set the Dock to Fill and let the DGV handle scrolling on it's own. I don't think it will do the jumping thing anymore. Otherwise, I guess you could just size it so it's less than the panel and let it do the scrolling on it's own.

jhunter
+2  A: 

I am guessing that you are setting the AutoScroll property of the panel to true. When you do so, switching applications resets the scroll position to zero and the panel resets its position.

If you switch off AutoScroll and add your own scrollbar you can set the scrollbar's maximum and minimum to match the requirements for the panel, then set the panel's scroll values in the Scroll event of the scrollbar. This is not reset when you switch windows.

Something like:

private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
    panel1.VerticalScroll.Value = vScrollBar1.Value;
}

This was a new one on me and I had to recreate it. I might have to add an article to my site about it :-)

BlackWasp
Thanks for that - it looks promising. We've got some issues with flickering when using the VScrollBar, but I'm sure we can come up with something that works. It certainly stops the original jumping problem.
+5  A: 

This is caused by the ScrollToControl event being fired automatically by the ScrollableControl class, and the event handler scrolling to show the top left of the control that got focus. This behavior is not helpful when the scrollable container control only contains one control. I was very frustrated by this behavior until I found out how to stop it.

The way to stop this behavior is to override the ScrollToControl event handler, like this:

class PanelNoScrollOnFocus : Panel
{
    protected override System.Drawing.Point ScrollToControl(Control activeControl)
    {
        return DisplayRectangle.Location;
    }
}

Replace your panel control with this panel control. Done.

skypecakes
Thanks, had been hitting my head on the desk hard for last hour. Your solution saved the trip to the hospital! :)
virtualmic
A: 

Thanks skypecakes, that worked beautifully :) Here's an edited version of your control that also keeps track of where the scrollbars where:


    class AutoScrollPanel : Panel
    {
     public AutoScrollPanel()
     {
      Enter += PanelNoScrollOnFocus_Enter;
      Leave += PanelNoScrollOnFocus_Leave;
     }

     private System.Drawing.Point scrollLocation;

     void PanelNoScrollOnFocus_Enter(object sender, System.EventArgs e)
     {
      // Set the scroll location back when the control regains focus.
      HorizontalScroll.Value = scrollLocation.X;
      VerticalScroll.Value = scrollLocation.Y;
     }

     void PanelNoScrollOnFocus_Leave(object sender, System.EventArgs e)
     {
      // Remember the scroll location when the control loses focus.
      scrollLocation.X = HorizontalScroll.Value;
      scrollLocation.Y = VerticalScroll.Value;
     }

     protected override System.Drawing.Point ScrollToControl(Control activeControl)
     {
      // When there's only 1 control in the panel and the user clicks
      //  on it, .NET tries to scroll to the control. This invariably
      //  forces the panel to scroll up. This little hack prevents that.
      return DisplayRectangle.Location;
     }
    }

This works only if there's just one control in the panel (although I haven't tested it with more then one control).

Sander