I have a custom control consisting of a filled rounded rectangle with text. (Actual control is more complicated, but the code shown here has the sames symptoms.) I linked the control instances to a panel and made this group a child of another panel with AutoScroll = true. I thought this would be enough for the scroll behavior to work correctly, but if you scroll so that the left side of my control should go off the left side of the panel, it sticks and the control shrinks. The same thing happens when scrolling so that the control should go away at the top. (Below and to the right, it doesn't seem to be a problem). Here is sample code (link to System.Windows.Forms and System.Drawing required.) I am using Visual Studio 2010 with the .NET 4 client on Windows.
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace CustomControlScrollTest { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } // Form with a Dock = Fill panel with autoscroll turned on, and a nested panel // with few custom roundRectControls. public class Form1 : Form { Panel autoScrollPanel; Panel rectPanel; public Form1() { Size = new Size(300, 200); autoScrollPanel = new Panel(); autoScrollPanel.Dock = DockStyle.Fill; autoScrollPanel.AutoScroll = true; autoScrollPanel.AutoScrollMinSize = new Size(600, 450); autoScrollPanel.Resize += autoScrollPanel_Resize; autoScrollPanel.Scroll += autoScrollPanel_Scroll; Controls.Add(autoScrollPanel); rectPanel = new Panel(); rectPanel.Size = autoScrollPanel.AutoScrollMinSize; rectPanel.Controls.AddRange(new RoundRectControl[] { new RoundRectControl(), new RoundRectControl(), new RoundRectControl(), new RoundRectControl(), new RoundRectControl() }); foreach (Control c in rectPanel.Controls) { c.Click += c_Click; } autoScrollPanel.Controls.Add(rectPanel); placeBoxes(); } // we want to be able to recalculate the boxes position at any time // in the real program this occurs due to model changes void c_Click(object sender, EventArgs e) { placeBoxes(); } void autoScrollPanel_Scroll(object sender, ScrollEventArgs e) { Refresh(); } void autoScrollPanel_Resize(object sender, EventArgs e) { Refresh(); } private void placeBoxes() { for (int i = 0; i < rectPanel.Controls.Count; ++i) { int j = i + 1; var node = rectPanel.Controls[i] as RoundRectControl; if (node != null) { node.Title = "Hello (" + j + ")"; node.Location = new Point(i * 100, j * 75); node.Visible = true; } } } } // A rounded rectangle filled blue with a black border and white text // the size is determined by the text public class RoundRectControl : Control { public RoundRectControl() { var f = SystemFonts.MessageBoxFont; titleFont = new Font(f.Name, f.SizeInPoints + 2, FontStyle.Bold, GraphicsUnit.Point); ResizeRedraw = true; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var g = e.Graphics; var left = e.ClipRectangle.X; var right = left + titleWidth + 2 * radius; var top = e.ClipRectangle.Y; var bottom = top + nodeHeight + 2 * radius; var r2 = 2 * radius; using (var path = new GraphicsPath()) { path.AddArc(left, bottom - r2, r2, r2, 90, 90); path.AddArc(left, top, r2, r2, 180, 90); path.AddArc(right - r2, top, r2, r2, 270, 90); path.AddArc(right - r2, bottom - r2, r2, r2, 0, 90); path.CloseFigure(); g.FillPath(titleBrush, path); g.DrawPath(borderPen, path); } g.DrawString(title, titleFont, titleTextBrush, left + radius, top + radius); } private string title; public string Title { get { return title; } set { title = value; Size = getSize(); Invalidate(); } } private Brush titleBrush = Brushes.Blue; private Brush titleTextBrush = Brushes.White; private Pen borderPen = Pens.Black; private Size getSize() { var g = CreateGraphics(); var titleSize = g.MeasureString(title, titleFont); titleWidth = (int)titleSize.Width; nodeHeight = (int)titleSize.Height; return new Size(titleWidth + 2 * radius + 1, nodeHeight + 2 * radius + 1); } public override Size GetPreferredSize(Size proposedSize) { return getSize(); } private int titleWidth; private int nodeHeight; private Font titleFont; private int radius = 5; } }