Add control at runtime to user control's inner panel - vb.net

I have a user control that contains 2 panels. Panel1 is the parent for Panel2 so Panel2 is placed inside the Panel1 container. Now, at runtime, I want to add controls to my user control. These new controls must be placed inside Panel2. Addings controls with myUserControl.Controls.Add would normally put the new controls into the user control itself and not inside Panel2. I would like Panel2 to be the default container for all controls that are added to the user control at runtime. How to do this?

You can override OnControlAdded, verify whether the UC Handle is already created (InitiaizeComponent() has already being executed, so all child Controls added in the Designer have already been added to the UC's Controls collection), then add the new Control to Panel2.Controls collection:
Public Class MyUSerControl
Inherits UserControl
Protected Overrides Sub OnControlAdded(e As ControlEventArgs)
If IsHandleCreated AndAlso e.Control IsNot Panel1 Then
Panel2.Controls.Add(e.Control)
End If
MyBase.OnControlAdded(e)
End Sub
End Class
Or, you could add a public method that performs this action:
Dim btn1 = New Button() With {.Text = "Button1", .Name = "Button1"}
Dim btn2 = New Button() With {.Text = "Button2", .Name = "Button2"}
myUSerControl.AddControls(btn1)
' Or
myUSerControl.AddControls({btn1, btn2})
Public Class MyUSerControl
Inherits UserControl
Public Sub AddControls(ParamArray newControls As Control())
Panel2.Controls.AddRange(newControls)
End Sub
End Class

Related

How to stop UserControl inside panel from opening new instance

I have form formmain. Inside panel2 of formmain I want to open UserControl named create_item using Button Button2. The code is:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim uc = New create_item
Panel2.Controls.Add(uc)
uc.BringToFront()
End Sub
Problem is if I click Button2 two times, two different UserControls open. If Button2 is clicked and UserControl create_item is already open then I want it to show it in front of the other controls. How can I do that? Please help. Thank you in advance.
Try the following:
Create a Windows App (.NET Framework)
Open Solution Explorer
In VS menu, click View
Select Solution Explorer
Open the Toolbox
In VS menu, select View
Select Toolbox
Add 2 Buttons to Form1 (ButtonShowUserControl1 and ButtonShowUserControl2)
Double-click each button to add the event handler to the form
Add a Panel to Form1 (name: Panel2)
Create 2 UserControls (name: UserControl1 and UserControl2) - design as desired.
For testing, one can add a label to each UserControl and set the text property to a unique value such as "This is UserControl 1" or "This is UserControl 2".
Rename Form1.vb to FrmMain.vb
In Solution Explorer, right-click Form1.vb
Select Rename (name: FrmMain.vb)
When prompted You are renaming a file. Would you also like to perform a rename in this project of all references to the code element "Form1.vb", select Yes
Select one of the options below:
Option 1 (FrmMain.vb)
This option creates an instance of each type of UserControl and adds it to the Panel when the corresponding Button is clicked. To ensure that only 1 instance of each type of UserControl is added, it uses Find (which searches based on the name of the UserControl) to check if an instance already exists. Since more than 1 UserControl may exist on the Panel, it uses BringToFront to ensure that the desired UserControl is shown.
Public Class FrmMain
Private Function BringDesiredUserControlToFront(ucName As String) As Boolean
'check if UserControl already exists on the Panel
If Panel2.Controls.Count > 0 Then
'find Controls matching the specified name
Dim ctls As Control() = Panel2.Controls.Find(ucName, False)
If ctls IsNot Nothing AndAlso ctls.Count > 0 Then
'there should only be 1 instance of this Control
Dim ctl As Control = ctls(0)
'bring UserControl to front
ctl.BringToFront()
Return True
End If
End If
Return False
End Function
Private Sub ButtonShowUserControl1_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl1.Click
Debug.WriteLine($"Panel2.Controls.Count: {Panel2.Controls.Count}")
If Not BringDesiredUserControlToFront("UserControl1") Then
'create new instance
Dim uc As UserControl1 = New UserControl1()
'set property
uc.Name = "UserControl1"
'add to Panel
Panel2.Controls.Add(uc)
'show
uc.Show()
'in case other controls exist, bring this one to front
'if desired, one can check if other controls exist
'and only execute the following statement if other controls exist
uc.BringToFront()
End If
End Sub
Private Sub ButtonShowUserControl2_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl2.Click
Debug.WriteLine($"Panel2.Controls.Count: {Panel2.Controls.Count}")
If Not BringDesiredUserControlToFront("UserControl2") Then
Debug.WriteLine("Creating new instance of UserControl2")
'create new instance
Dim uc As UserControl2 = New UserControl2()
'set property
uc.Name = "UserControl2"
'add to Panel
Panel2.Controls.Add(uc)
'show
uc.Show()
'in case other controls exist, bring this one to front
'if desired, one can check if other controls exist
'and only execute the following statement if other controls exist
uc.BringToFront()
End If
End Sub
End Class
Option 2 (FrmMain.vb)
This option creates an instance of each type of UserControl and adds it to the Panel when the corresponding Button is clicked. To ensure that only 1 instance of each type of UserControl is added, it uses a For Each to loop through all of the controls and check if an instance already exists. Since more than 1 UserControl may exist on the Panel, it uses BringToFront to ensure that the desired UserControl is shown.
Public Class FrmMain
Private Sub ButtonShowUserControl1_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl1.Click
Dim uc As UserControl1 = Nothing
Debug.WriteLine($"Panel2.Controls.Count: {Panel2.Controls.Count}")
'check if UserControl already exists on the Panel
If Panel2.Controls.Count > 0 Then
For Each ctl In Panel2.Controls
If TypeOf (ctl) Is UserControl1 Then
'create reference
uc = CType(ctl, UserControl1)
Exit For
End If
Next
End If
If uc Is Nothing Then
'UserControl doesn't exist on Panel
'create new instance
uc = New UserControl1()
'add to Panel
Panel2.Controls.Add(uc)
'show
uc.Show()
End If
'show
uc.BringToFront()
End Sub
Private Sub ButtonShowUserControl2_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl2.Click
Dim uc As UserControl2 = Nothing
Debug.WriteLine($"Panel2.Controls.Count: {Panel2.Controls.Count}")
'check if UserControl already exists on the Panel
If Panel2.Controls.Count > 0 Then
For Each ctl In Panel2.Controls
If TypeOf (ctl) Is UserControl2 Then
'create reference
uc = CType(ctl, UserControl2)
Exit For
End If
Next
End If
If uc Is Nothing Then
'UserControl doesn't exist on Panel
'create new instance
uc = New UserControl2()
'add to Panel
Panel2.Controls.Add(uc)
'show
uc.Show()
End If
'show
uc.BringToFront()
End Sub
End Class
Option 3 (FrmMain.vb)
This option only has 1 UserControl on the Panel at a time. If a UserControl already exists on the Panel, it is removed and disposed prior to adding a different one.
Public Class FrmMain
Private _currentUserControl As UserControl = Nothing
Private Sub ShowDesiredUserControl(uc As UserControl)
If _currentUserControl IsNot Nothing Then
'remove existing UserControl
Panel2.Controls.Remove(_currentUserControl)
'dispose
_currentUserControl.Dispose()
End If
'add UserControl to Panel
Panel2.Controls.Add(uc)
'set value
_currentUserControl = uc
'show
uc.Show()
Debug.WriteLine($"Panel2.Controls.Count: {Panel2.Controls.Count}")
End Sub
Private Sub ButtonShowUserControl1_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl1.Click
ShowDesiredUserControl(New UserControl1())
End Sub
Private Sub ButtonShowUserControl2_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl2.Click
ShowDesiredUserControl(New UserControl2())
End Sub
End Class
Option 4 (FrmMain.vb)
This option only has 1 UserControl on the Panel at a time. If a UserControl already exists on the Panel, it is removed and disposed prior to adding a different one. It's similar to Option 3.
Public Class FrmMain
Private _currentUserControl As UserControl = Nothing
Private Sub ButtonShowUserControl1_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl1.Click
If _currentUserControl IsNot Nothing Then
'remove existing UserControl
Panel2.Controls.Remove(_currentUserControl)
'dispose
_currentUserControl.Dispose()
End If
'create new instance
_currentUserControl = New UserControl1()
'add UserControl to Panel
Panel2.Controls.Add(_currentUserControl)
'show
_currentUserControl.Show()
End Sub
Private Sub ButtonShowUserControl2_Click(sender As Object, e As EventArgs) Handles ButtonShowUserControl2.Click
If _currentUserControl IsNot Nothing Then
'remove existing UserControl
Panel2.Controls.Remove(_currentUserControl)
'dispose
_currentUserControl.Dispose()
End If
'create new instance
_currentUserControl = New UserControl2() 'create new instance
'add UserControl to Panel
Panel2.Controls.Add(_currentUserControl)
'show
_currentUserControl.Show() 'show
End Sub
End Class
Resources
Scope in Visual Basic

Create a function that shows user controls in a panel

I created several user controls that i want to display on a main panel.
Thus, I have this function that takes in input the control I want to display by setting it to visible, and visible = false for all other ones :
Public Sub ShowControl(ByVal Controle As Control)
MainPanel.BringToFront()
Try
With MainPanel
For Each contr As Control In .Controls
If contr.Name <> Controle.Name Then
contr.Visible = False
Else
' Display the control
contr.Visible = True
End If
Next
End With
Catch ex As Exception
End Try
It works well when my panel has different user controls like this :
Public WithEvents uc1 As New User_Control1
Public WithEvents uc2 As New User_Control2
Public WithEvents uc3 As New User_Control3
MainPanel.Controls.Add(uc1)
MainPanel.Controls.Add(uc2)
MainPanel.Controls.Add(uc3)
But not if I create several instances from the same user control :
Public WithEvents uc1 As New User_Control1
Public WithEvents uc2 As New User_Control1
Public WithEvents uc3 As New User_Control1
MainPanel.Controls.Add(uc1)
MainPanel.Controls.Add(uc2)
MainPanel.Controls.Add(uc3)
I know that this is because in my function the name Controle.name will remain the same (User_Control1), but is there any way to make it works ?

Loop through custom control classes

I would like to use a function at startup to apply several properties to a custom control class.
Public Shared Function ToggleSwitchProperties()
Form1.ToggleSwitch1.OnText = "ON"
Form1.ToggleSwitch1.OnFont = New Font(Form1.Font.FontFamily, 8, FontStyle.Bold)
Form1.ToggleSwitch1.OnForeColor = Color.White
Form1.ToggleSwitch1.OffText = "OFF"
Form1.ToggleSwitch1.OffFont = New Font(Form1.Font.FontFamily, 8, FontStyle.Bold)
Form1.ToggleSwitch1.OffForeColor = Color.White
End Function
This is what I have so far. I would like to apply these settings to 5 other toggle switches (named ToggleSwitch1 to ToggleSwitch5) but, for some reason, I can't find a solution.
Some more information about the situation:
I created a Form with a TabControl on it and the switches are located on TabPage1.
The toggle switches are custom made (JCS.ToggleSwitch from CodeProject)
You can group your controls in a single array and iterate this temporary collection to set the properties af all the controls referenced. You can call these controls by name even if they're not direct child of the Parent Form (they are child of another container, a TabPage of a TabControl, in this case).
Note that you're using a Function that doesn't return a value, which makes it a Sub instead.
A static (Shared) method doesn't seem appropriate to reference instances of controls.
See also whether this method needs to be Public. Probaly not.
Let's make it internal (Friend) and see if it's ok.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ToggleSwitchProperties()
End Sub
Friend Sub ToggleSwitchProperties()
For Each tSwitch As ToggleSwitch In {ToggleSwitch1, ToggleSwitch2, ToggleSwitch3, ToggleSwitch4, ToggleSwitch5}
tSwitch.OnText = "ON"
tSwitch.OnFont = New Font(Form1.Font.FontFamily, 8, FontStyle.Bold)
tSwitch.OnForeColor = Color.White
tSwitch.OffText = "OFF"
'(... all other settings ...)
Next
End Function
Option 2.
You could also use a recursive method that searches and sets the properties of all the controls of a specific type, which are inside a container or any of its sub-containers (a TabPage inside a TabControl, in this case).
In this case, you don't need to specify all the names of the controls affected: the method will modifiy all the controls it finds inside the specified container.
In your case, you could call this method using the TabControl that contain your ToggleSwitch control as argument:
EDIT:
The code was missing a cast: Dim tSwitch = DirectCast(ctl, ToggleSwitch), which prevents the code from working as expected. Now added back.
ToggleSwitchProperties(TabControl1)
Friend Sub ToggleSwitchProperties(ctlParent As Control)
If (ctlParent Is Nothing) OrElse (Not ctlParent.HasChildren) Then Return
For Each ctl As Control In ctlParent.Controls.OfType(Of Control)
If TypeOf ctl Is ToggleSwitch Then
Dim tSwitch = DirectCast(ctl, ToggleSwitch)
tSwitch.OnText = "ON"
tSwitch.OnFont = New Font(Form1.Font.FontFamily, 8, FontStyle.Bold)
'(... all other settings ...)
Else
If ctl.HasChildren Then
ToggleSwitchProperties(ctl)
End If
End If
Next
End Sub

How to access public subs of dynamically loaded user control in a panel

I have a panel and a button in a form and 2 user controls, I dynamically loaded the first user control in the panel then inside the userControl1 I have a method that I want to access when I clicked the button in the form and then change the displayed user control to userControl2 in the panel, how should I do that?
form1 code:
Public Class form1
Private Sub form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim control1 = New UserControl1
Panel1.Controls.Add(control1)
control1.Location = New Point(0, 0)
control1.Size = New Point(1351, 533)
End Sub
End Class
UserControl1 Code:
Public Class UserControl1
Public Sub doSomething()
'Do something'
End Sub
End Class
OK, I'll take as much as I can from your question and show you an example, there are many different ways you could do this, thus, may not answer your question 100% but will give you enough to get what you want.
I'm making an assumption that you only have one control1 and one control2.
My example will alternate, and access a sub routine in the active (shown) usercontrol on each click on the main form button.
In a module I would put:
Public control1 As New UserControl1
Public control2 As New UserControl2
In UserControl1 put:
Public Sub DoSomething()
Me.BackColor = Color.Black
End Sub
In UserControl2 put:
Public Sub DoSomething()
Me.BackColor = Color.White
End Sub
In your FormLoad event put:
control1.Location = New Point(0, 0)
control1.Size = New Point(1351, 533)
Panel1.Controls.Add(control1)
In your Button1 click event put:
Select Case Panel1.Contains(control1)
Case True
'Remove UserControl1 - Add UserControl2
Panel1.Controls.Remove(control1)
control2.Location = New Point(0, 0)
control2.Size = New Point(1351, 533)
Panel1.Controls.Add(control2)
control2.DoSomething()
Case False
'Remove UserControl2 - Add UserControl1
Panel1.Controls.Remove(control2)
control1.Location = New Point(0, 0)
control1.Size = New Point(1351, 533)
Panel1.Controls.Add(control1)
control1.DoSomething()
End Select
The above is checking which UserControl is in the panel and alternating it and calling the 'DoSomething'. This is just an example to give you an idea. What you want may be different, you may have a button in your second UserControl and if so, amend the switch code to suit.

Add click to control inside a panel

Morning,
I am trying to add a click event for the controls that i add into my Panel dynamically. The control i add is a custom class that i have created called 'Slide'.
Here is the code where i build the Slide class that will be added to the panel:
Dim thisControl As New Slide()
With thisControl
.Dock = System.Windows.Forms.DockStyle.Left
.Thumbnail.Image = ThisSlide
.Thumbnail.BackColor = Color.Transparent
.Caption.Text = "Slide" & radSlides.SelectedIndex
.Ordinal = pnlScheduledSlides.Controls.Count.ToString
.Duration = Conversion.Int(20)
.Content = pContent
End With
Then I add 'thisControl' to the panel:
pnlScheduledSlides.Controls.Add(thisControl)
I am wanted to be able to click on a Slide inside the panel so that i can add some functionality to be able to add/remove the slide.
You need a dinamic event handler
Addhandler thisControl.Click, AddressOf your_dinamic_click
Where your_dinamic_click is something like this:
Private sub your_dinamic_click(sender As Object, e As EventArgs)
I'm supposing that your Slide control raises a "click" event