25

I have a System.Windows.Forms.Panel with some content.

I am trying to programmatically scroll the panel (vertically) either up or down.

I have tried setting the AutoScrollPosition property to a new Point on the panel but that doesn't seem to do it.

I have the AutoScroll property set to true.

I even tried to set the VerticalScroll.Value twice as suggested here, but that doesn't seem to work either.

This is what I am currently doing:

//I have tried passing both positive and negative values.
panel.AutoScrollPosition = new Point(5, 10);

The X and Y values on AutoScrollPosition remain 0 and 0.

Any help or direction on this would be greatly appreciated it.

Thanks in advance,

Marwan

Community
  • 1
  • 1
Marwan مروان
  • 2,163
  • 8
  • 30
  • 40
  • did you try adding/setting control.Focus() at bottom of your form. – Access Denied Jul 19 '13 at 18:39
  • 2
    AutoScroll does what it says, it is *auto*. If you want to control the scrolling yourself then set it back to False. Set the AutoScrollMinSize property instead, now assigning AutoScrollPosition will work. – Hans Passant Jul 19 '13 at 22:29

8 Answers8

29

Here is a solution. I guess you can scroll your Panel by arbitrary position using Win32 however there is a simple trick to help you achieve your requirement here:

public void ScrollToBottom(Panel p){
  using (Control c = new Control() { Parent = p, Dock = DockStyle.Bottom })
     {
        p.ScrollControlIntoView(c);
        c.Parent = null;
     }
}
//use the code
ScrollToBottom(yourPanel);

Or use extension method for convenience:

public static class PanelExtension {
   public static void ScrollToBottom(this Panel p){
      using (Control c = new Control() { Parent = p, Dock = DockStyle.Bottom })
      {
         p.ScrollControlIntoView(c);
         c.Parent = null;
      }
   }
}
//Use the code
yourPanel.ScrollToBottom();

UPDATE

If you want to set the exact position, modifying the code above a little can help:

//This can help you control the scrollbar with scrolling up and down.
//The position is a little special.
//Position for scrolling up should be negative.
//Position for scrolling down should be positive
public static class PanelExtension {
    public static void ScrollDown(this Panel p, int pos)
    {
        //pos passed in should be positive
        using (Control c = new Control() { Parent = p, Height = 1, Top = p.ClientSize.Height + pos })
        {
            p.ScrollControlIntoView(c);                
        }
    }
    public static void ScrollUp(this Panel p, int pos)
    {
        //pos passed in should be negative
        using (Control c = new Control() { Parent = p, Height = 1, Top = pos})
        {
            p.ScrollControlIntoView(c);                
        }
    }
}
//use the code, suppose you have 2 buttons, up and down to control the scrollbar instead of clicking directly on the scrollbar arrows.
int i = 0;
private void buttonUp_Click(object sender, EventArgs e)
{
   if (i >= 0) i = -1;
   yourPanel.ScrollUp(i--);
}
private void buttonDown_Click(object sender, EventArgs e)
{
   if (i < 0) i = 0;
   yourPanel.ScrollDown(i++);
}

Another solution you may want to use is using Panel.VerticalScroll.Value. However I think you need more research to make it work as you expect. Because I can see once changing the Value, the scrollbar position and control position don't sync well. Notice that Panel.VerticalScroll.Value should be between Panel.VerticalScroll.Minimum and Panel.VerticalScroll.Maximum.

King King
  • 61,710
  • 16
  • 105
  • 130
  • Thanks for the quick answer. I guess my question was not very clear. I am trying to scroll up or down the panel programmatically, and not just to the bottom. I just edited my question to reflect that. Sorry about that, but thank you for the helpful information. – Marwan مروان Jul 19 '13 at 19:31
  • 1
    I have added your code, and wired up the buttons but the panel is not scrolling. When I debug through the code, your functions are being called but the panel does not move. I am still trying working on it. – Marwan مروان Jul 19 '13 at 22:13
  • @Marwanمروان Remember to set `AutoScroll = true`. I tested the code and it works OK. – King King Jul 19 '13 at 22:20
  • You are a god! You saved me again...Thanks so much. Before I came back to see your last comment, I had set up the button clicks to modify the actual location of the panel content...THANKS AGAIN!!! – Marwan مروان Jul 19 '13 at 22:43
  • @Marwan you're welcome. In fact there seem to be more obvious solutions: if using `win32 function` we have `SetScrollInfo` but I've tested this, it's a little tricky, a `Panel` also has a `VerticalScroll` property, its name suggests us its ability to modify something relating to `vertical scrollbar` and it does have a `Value` property for us to change. However the position of control in `Panel` doesn't sync well with the position of the vertical scrollbar. You can dig into those approaches to have a better solution if possible. – King King Jul 19 '13 at 22:53
  • I have tried the VerticalScroll property but I could not make it work. See this link: http://stackoverflow.com/questions/15559914/horizontalscroll-value-wont-programmatically-set – Marwan مروان Jul 19 '13 at 23:41
  • Both vertical and horizontal scroll bars are showing when I set the AutoScroll property to true. I have tried setting the Enabled and Visible properties on the panel.VerticalScroll and panel.HorizontalScroll to false but they still show. Any advice? – Marwan مروان Jul 19 '13 at 23:42
  • @Marwanمروان I have no idea on such problem, in fact I've encountered it before but still be stuck. We hardly change the default scrollbar. A workaround is whenever you add controls to and remove controls from your panel, check if `VerticalScroll.Visible = true` and `HorizontalScroll.Visible = true`, we can assign a new `Region` for the Panel to cut-off the scrollbars. Something like this: `Panel.Region = new Region(new Rectangle(0,0,Panel.Width - SystemInformation.VerticalScrollBarWidth, Panel.Height - SystemInformation.HorizontalScrollBarHeight));`. – King King Jul 20 '13 at 00:55
  • Of course, you should add a `SystemInformation.VerticalScrollBarWidth` to `Panel.Width` and `SystemInformation.HorizontalScrollBarHeight` to `Panel.Height` before to keep the size of your `Panel` the same after cutting-off the scrollbars. – King King Jul 20 '13 at 00:55
  • Thanks again for all your help! Where should I add the `SystemInformation.VerticalScrollBarWidth` to `Panel.Width`? Which event should have that information? – Marwan مروان Jul 23 '13 at 21:20
  • @Marwanمروان Doing so to keep your Panel Width the same after cutting off the vertical scrollbar. In fact whenever the Scroll bar visibility changes (toggles between Visible and Invisible), you have to update the Panel Region accordingly. However there is not any event supported to notify when `Panel.VerticalScroll.Visible` changes, I recommend you check its visibility and perform according update on the Region whenever you add/remove your controls from your Panel. For your convenience, I uploaded a demo to demonstrate it here http://www.mediafire.com/?ipvowiokitn4tlb (you need VS 2008) – King King Jul 24 '13 at 03:04
7

This surprisingly works! NOTE THE MINUS SIGN in the code. There is strange behavior in setting scroll position. If you set the position to exact value (50), it goes negative when you read it next time (-50). So you have to invert it before setting new scroll value.

Scroll down:

private void ButtonScrollDown_OnClick(object sender, EventArgs e)
{
    Point current = yourScrollPanel.AutoScrollPosition;
    Point scrolled = new Point(current.X, -current.Y + 10);
    yourScrollPanel.AutoScrollPosition = scrolled;
}

Scroll up similarly, (-current.Y - 10)

Milan Švec
  • 1,675
  • 17
  • 21
  • 2
    Work this? `panel1.AutoScrollPosition = new Point(-panel1.AutoScrollPosition.X + 200);` – Vitokhv Dec 23 '18 at 09:15
  • 1
    @Vitokhv: A sweet short way. :) – D J Jun 29 '20 at 05:25
  • I've got a control that needs X and Y scrolling. Using Point(Math.Abs(current.X), -current.Y + 10); instead of just current.X made it behave nicer. Otherwise, the non-scrolled coordinate resets back to 0 (or negative). – edhubbell Apr 14 '21 at 18:50
5

If you have a class that derives from Panel, then call these two protected methods to scroll the panel:

// The bottom is off screen; scroll down. These coordinates must be negative or zero.
SetDisplayRectLocation(0, AutoScrollPosition.Y - item.BoundingRect.Bottom + ClientRectangle.Bottom);
AdjustFormScrollbars(true);

In my example, item.BoundingRect.Bottom is the Y coordinate of the bottom of a thumbnail, and I need to scroll the panel down so that the whole thumbnail is visible.

@King King's solution of creating a temporary Control just so that scrolling could be done seemed "heavy" to me. And @Hans Passant's suggestion of setting AutoScrollMinSize and AutoScrollPosition didn't work for me.

Leave AutoScroll to its default value of 'true'.

Ron
  • 1,888
  • 20
  • 25
4

Try this:- panel.ScrollControlIntoView(childcontrol);

This should work. childcontrol is the particular control that you want to show in your display area.

3

Setting the value of the HorizontalScroll property and then using the method ScrollControlIntoView works for me:

lpanel.HorizontalScroll.Value = 100;
lpanel.ScrollControlIntoView(lpanel);
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
WLE
  • 31
  • 1
1

I had an issue where I couldnt get my panel to scroll back to top . I tried many things to try and get the panel to scroll back to the top after populating it with many controls.

Nomatter what I did it always put the VScroll bar to the bottom.

After exhaustive testing I found it was because my controls had the TabStop property set to true (default on user controls) was causing the issue.

Setting TabStop to false fixed it.

Christopher Townsend
  • 1,527
  • 1
  • 13
  • 37
  • When you add an answer on stackoverflow and aren't sure if it will be useful to someone... 3 years later you just solve my problem related to usercontrol and scrolling! – vigneault.charles Apr 02 '20 at 22:34
0

Use @King King Answered Code and if you want to hide horizontal and vertical scroll bar, just apply the below code in the constructor or initialization.

        yourPanel.AutoScroll = false;
        yourPanel.HorizontalScroll.Maximum = 0;
        yourPanel.HorizontalScroll.Visible = false;
        yourPanel.VerticalScroll.Maximum = 0;
        yourPanel.VerticalScroll.Visible = false;
        yourPanel.AutoScroll = true;
suneel ranga
  • 467
  • 4
  • 6
0

Create an control that sits slightly outside the visible area (so -1 at the top and clientsize+1 ) and then call ScrollControlIntoView:

public static class PanelExtension {
public static void ScrollDown(this Panel p)
{

    using (Control c = new Control() { Parent = p, Height = 1, Top = p.ClientSize.Height + 1 })
    {
        p.ScrollControlIntoView(c);                
    }
}
public static void ScrollUp(this Panel p )
{

    using (Control c = new Control() { Parent = p, Height = 1, Top = -1})
    {
        p.ScrollControlIntoView(c);                
    }
}
}
    //use the code, suppose you have 2 buttons, up and down to control the scrollbar instead of clicking directly on the scrollbar arrows.

        private void buttonUp_Click(object sender, EventArgs e)
{

   yourPanel.ScrollUp();
}
private void buttonDown_Click(object sender, EventArgs e)
{

   yourPanel.ScrollDown();
}

with yourpanel.SetAutoScrollMargin(1, 1); you can set very fine scrolling steps and then take a timer to call the srolling when buttons are down

Marc
  • 1
  • 1