Quite often we have a need for a VB control that has some requirements that don't quite exist within the current control set. Recently a client required that all data-entry controls be on a single page, not across multiple tabs, and the page should scroll much like the page you're reading now.
Rather than doing the quick large Picturebox inside a smaller Picturebox with scrollers, and duplicating the same across multiple forms, I decided to create a quick user control to simplify the effort on the second and third forms.
Little did I know that I was in for a challenge, and spent much more time working on this than planned.
The First Obstacle
Not many people are aware that user controls have two working modes; Design mode and Running mode. The user-control code runs in both modes however Debugging only works in running mode; code breaks will not trigger during design time. This obviously leads to problems testing; however you often can replicate design time actions in the run time to fully debug specific options.
Most of the time you need to set up the control properly, so to start, add a Component class to your project and modify the code as below.
Imports System.ComponentModel Imports System.Drawing Imports System.Drawing.Drawing2D Imports System.ComponentModel.Design Imports System.Windows.Forms <Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", GetType(IDesigner))> _ Public Class TestControl Inherits Control End Class
This prepares the control for the designer, and allows you to add controls to it. Now that our base user control is ready, let's start with our experiments. (Thanks to Hannes for showing me this when I started).
First try was a user control with a Picturebox inside a Picturebox. This works like a charm on the form.
In the class Designer we add a Picturebox, only one for now so that we can test. But aren't we doing a Picturebox inside a Picturebox? Yes we still going to use that method and the Component class is the first Object and the smaller holder of the two. Our Picturebox is the second and larger of the two, which will ultimately hold the final controls.
To start we need to initialize the controls.
Public Sub New() ' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. Me.Controls.Add(PictureBox1) End Sub
And now let's expose a few properties of the Picturebox so that we can play with it in the designer.
Public Property Z_Width() As Integer Get Return PictureBox1.Width End Get Set(ByVal value As Integer) PictureBox1.Width = value End Set End Property Public Property Z_Height() As Integer Get Return PictureBox1.Height End Get Set(ByVal value As Integer) PictureBox1.Height = value End Set End Property Public Property Z_Top() As Integer Get Return PictureBox1.Top End Get Set(ByVal value As Integer) PictureBox1.Top = value End Set End Property Public Property Z_Left() As Integer Get Return PictureBox1.Left End Get Set(ByVal value As Integer) PictureBox1.Left = value End Set End Property
Lets test this quickly.
NOTE: even if we added the Scrollers at this time, they are not active in the designer and you would still need to adjust the position of the inner controls via the properties. So the Scrollers are left out until we know where we going to go.
Build the control, and then add it to a form, Adjust the Z_width and Z_Height so that our Picturebox is wider and higher than the control. Now add a few other controls to our control. Adjust Z_top and Z_left to move our inner control around.
Now we're shifting the Picturebox about; remember, negative values will pull the inner Picturebox up and left, exposing the hidden parts. However, there's a problem, none of the added controls are shifting around.
The problem is they are all children controls at the same level as the Picturebox, and not children of the Picturebox, and because of this they do not move with it.