Clear values of controls dynamically - vb.net

I would like to know if there is a algoritm for clearing all the values dynamically of a Panel without the need to do it manually. And recursive if it 's possible. I have this idea in my mind but it doesn 't compile obviously.
Private Sub ClearAll(ByRef panel As Control)
For Each objControl As Control In panel.Controls
If (TypeOf objControl Is Panel) Then
ClearAll(objControl)
End If
If (TypeOf objControl Is CheckBox Or TypeOf objControl Is RadioButton) Then
objControl.Checked = False
End If
If (TypeOf objControl Is TextBox) Then
objControl.Clear()
End If
Next
End Sub

You're close!
when you recurse, you don't have to check the type, all Control objects have .controls and it doesn't hurt to check them (speed gain isn't worth code bloat)
In VB use CType.
Then you're done! (for clarity: rename the variable 'panel' to 'ctl' or the like; it now won't always be a panel, could be a groupbox)
Private Sub ClearAll(ByRef panel As Control)
For Each objControl As Control In panel.Controls
ClearAll(objControl)
If TypeOf objControl Is Checkbox then
ctype(objControl,Checkbox).Checked = False
End If
If TypeOf objControl Is RadioButton then
ctype(objControl,RadioButton).Checked = False
End If
If TypeOf objControl Is TextBox Then
ctype(objControl,textbox).Clear()
End If
' etc ... e.g., if Listbox, ctype(...).SelectedIndex=-1, then if Dropdown...
Next
End Sub
Ideally, winforms controls would implement simple interfaces that allowed controlling stuff common to them.
all controls - implement ISetToDefault with .Reset method which clears textbox, checkbox, listbox, etc.
list/combo: IHaveListItems with all properties of .List on combo/listbox to allow operating lists as single type (in wf, the two are frustratingly different types!)
text/combo: IHaveUserEnteredText with a .Text property
all controls - IHaveValue with a .Value property as string (would be .ToString of Boolean or etc).
groupbox/check/option - IHaveCaption with .Caption, you get the idea.
But we don't get to rewrite winforms now do we...

You can try this so you can add many region for exemple if you have TabControl or GroupeControle :
Public Shared Sub ClearChamps(ByVal myObject As Control)
'#Region "Controls XtraTabControl"
'#End Region
'#Region "Controls XtraTabPage"
' #Region "Controls GroupControl"
'****les controles de la GroupControl
If TypeOf myObject Is Control Then
Dim cont2 As Control = DirectCast(myObject, Control)
For Each myObject1 As [Object] In cont2.Controls
'If TypeOf myObject1 Is LookUpEdit Then
' '(myObject1 as LookUpEdit).ClosePopup() ;
' TryCast(myObject1, LookUpEdit).EditValue = Nothing
If TypeOf myObject1 Is TextBox Then
TryCast(myObject1, TextBox).Text = String.Empty
End If
If TypeOf myObject1 Is DataGridView Then
myObject1.Rows.Clear()
End If
If (TypeOf myObject1 Is CheckBox Or TypeOf myObject1 Is RadioButton) Then
myObject1.Checked = False
End If
Next
End If
' #End Region
'#Region "Groupbox"
'****les controles de la GroupControl
End Sub
you can use ClearChamps(ByVal myObject As Form) for target all controls in your form

Related

Select All Controls on Form

I am trying to implement a clear all button on a form that clears the textbox contents and unchecks all checkboxes. The issue is that the controls that need to be accessed are contained within Groupboxes and thus cannot be acessed via Me.Controls collection. I saw a similar post here: VB Uncheck all checked checkboxes in forms, but the answer seems to be more complex than I would expect it should be. Is there any easier way other than in that post.
I tried this code, which logically to me should work but it does not:
'Get textboes and clears them
For Each ctrGroupBoxes As Control In Me.Controls.OfType(Of GroupBox)
For Each ctrControls As Control In ctrGroupBoxes.Controls.OfType(Of TextBox)
ctrControls.Text = ""
Next
Next
'Get checkboxes and unchecks them
For Each ctrGroupBoxes As Control In Me.Controls.OfType(Of GroupBox)
For Each ctrControls As Control In ctrGroupBoxes.Controls.OfType(Of CheckBox)
DirectCast(ctrControls, CheckBox).Checked = False
Next
Next
I know the inner for loops work as I used it to clear each GroupBox individually for a different button on the form.
Any assistance would be appreciated.
Here's one option that should work regardless of the UI hierarchy:
Dim cntrl = GetNextControl(Me, True)
Do Until cntrl Is Nothing
Dim tb = TryCast(cntrl, TextBox)
If tb IsNot Nothing Then
tb.Clear()
Else
Dim cb = TryCast(cntrl, CheckBox)
If cb IsNot Nothing Then
cb.Checked = False
End If
End If
cntrl = GetNextControl(cntrl, True)
Loop
That will follow the Tab order on the form
A recursive function really isn't that difficult:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ClearForm(Me)
End Sub
Private Sub ClearForm(ByVal C As Control)
For Each ctl As Control In C.Controls
If TypeOf ctl Is TextBox Then
ctl.Text = ""
ElseIf TypeOf ctl Is CheckBox Then
DirectCast(ctl, CheckBox).Checked = False
ElseIf ctl.HasChildren Then
ClearForm(ctl)
End If
Next
End Sub
End Class

How to check empty controls within tabcontrol pages?

Some of my codes are from the answers I read here in stack-overflow, one difficulty I am facing is how to check empty controls inside Tab-control with 3 pages? I have created a function that validate if the input is empty:
VB.Net Function:
Public Shared Function ValidateInput(parent As Control)
Dim ctl As Control = Nothing
For Each ctl In parent.Controls
If TypeOf ctl Is TextBox And ctl.Text.Length = 0 Or TypeOf ctl Is ComboBox And ctl.Text.Length = 0 Then
Return ctl.Name
Exit For
'--------------------------------------------------------------------
'(1.) I want this statement to check if the control is type of Tabcontrol ang check for empty input. (I have 3 pages)
ElseIf TypeOf ctl Is TabControl Then
For Each tp As TabPage In frmClientInfo.TabControl1.TabPages
For Each ctr As Control In tp.Controls
If TypeOf ctr Is TextBox OrElse TypeOf ctr Is ComboBox Then
ctl.Name = ctr.Name
Return ctl.Name
Exit For
End If
Next
Next
'--------------------------------------------------------------------
Else
ctl = Nothing
End If
Next
Return ctl
End Function
Usage:
Dim x = Functions.ValidateInput(Me)
Dim ctrlinput As Object = Me.Controls.Find(x, True).FirstOrDefault()
If TypeOf ctrlinput Is TextBox Then
ctrlinput.focus()
ElseIf TypeOf ctrlinput Is ComboBox Then
ctrlinput.DroppedDown = True
ElseIf TypeOf ctrlinput Is TabControl Then 'If control is Tab-control
Dim y = Functions.ValidateInput(Me)
Dim xinput As Object = TabControl1.Find(y, True).FirstOrDefault()
If TypeOf xinput Is TextBox Then
xinput.focus()
ElseIf TypeOf xinput Is ComboBox Then
xinput.DroppedDown = True
End If
Else
MessageBox.Show("saveeee")
Call SaveTransaction()
End If
My condition that deals with the controls outside the tab-control works. But I cant get the controls inside the tab-control pages. I want to focus the control when the function detects an empty control inside the tab-control. Let say the empty control was detected on page 3 the system will automatically jump from page 1 to page 3 and focus the empty control. Any solution? Thanks.
A problem here is that a tab can have another container inside it, just like your tabcontainer contains... tabs. You can bypass this by going recursive, but then your function will return everything it finds, wherever it finds it.
Here's a recursive function which will return you a list of every textbox or combobox without text it finds where you call it:
Private Function GetEmptyControls(current As Control) As List(Of Control)
Dim list As New List(Of Control)
For Each ctrl As Control In current.Controls
If TypeOf ctrl Is ContainerControl Then
'if this control is a container, add every control this function might find inside it to your list
'this is what makes this function recursive
list.AddRange(GetEmptyControls(ctrl))
Else
'add this control if it's a textbox or combobox and there's no text
If ctrl.Text = "" AndAlso (TypeOf ctrl Is TextBox OrElse TypeOf ctrl Is ComboBox) Then
list.Add(ctrl)
End If
End If
Next
Return list
End Function
You can call it on your form or on a container inside your form, or adapt it to suit your needs. Have fun!

Loop controls in form and tabpages

I have form with tabcontrol and few tab pages which contain many settings in textboxes and checkboxes.
When user press Exit from this form I have to check if data was changed.
For that I thought to make a string on Enter of all values on form and compare it with string of all values on exit:
Private Function getsetupstring() As String
Dim setupstring As String = ""
For Each oControl As Control In Me.Controls
If TypeOf oControl Is CheckBox Then
Dim chk As CheckBox = CType(oControl, CheckBox)
setupstring &= chk.Checked.ToString
End If
If TypeOf oControl Is TextBox Then
setupstring &= oControl.Text.Trim.ToString
End If
Next
Return setupstring
End Function
But that code don't loop through controls which are on tab pages, only TabControl and few buttons which are on top of form.
What to do to get all controls listed so I can pick values?
Controls only contains the parent controls, not the respective children. If you want to get all the controls (parents and respective children), you can rely on a code on these lines:
Dim allControls As List(Of Control) = New List(Of Control)
For Each ctr As Control In Me.Controls
allControls = getAllControls(ctr, allControls)
Next
Where getAllControls is defined by:
Private Function getAllControls(mainControl As Control, allControls As List(Of Control)) As List(Of Control)
If (Not allControls.Contains(mainControl)) Then allControls.Add(mainControl)
If mainControl.HasChildren Then
For Each child In mainControl.Controls
If (Not allControls.Contains(DirectCast(child, Control))) Then allControls.Add(DirectCast(child, Control))
If DirectCast(child, Control).HasChildren Then getAllControls(DirectCast(child, Control), allControls)
Next
End If
Return allControls
End Function
Other alternative you have is relying on the Controls.Find method with the searchAllChildren property set to True.

vb.net find controls that begins with specified string in a form

I want to list all names of my buttons that begins with "btn" but these buttons are place in different panels. I have this in my mind
dim obj() as object in frmForm.Controls.Find(True,"btn*")
but I think it might be wrong..
First, the first parameter is the name and the second a bool which indicates whether you want to search recursively or not.
Second, there is no builtin way for this. I would use your own method, one like this:
Public Function FindControlStartsWith(root As Control, name As String, recursive As Boolean, comparison As StringComparison) As Control()
If root Is Nothing Then
Throw New ArgumentNullException("root")
End If
Dim controls = New List(Of Control)
Dim stack = New Stack(Of Control)()
stack.Push(root)
While stack.Count > 0
Dim c As Control = stack.Pop()
If c.Name.StartsWith(name, comparison) Then
controls.Add(c)
End If
If recursive Then
For Each child As Control In root.Controls
stack.Push(child)
Next
End If
End While
Return controls.ToArray()
End Function
Use it in this way:
Dim obj() As Control = FindControlStartsWith(Me, "BUT", True, StringComparison.OrdinalIgnoreCase)
I do something similar with the type of control, but it can easily be modified for name. Try the code below:
Private Sub findcontrols(ByVal root As Control)
For Each cntrl As Control In root.Controls
findcontrols(cntrl)
If cntrl.name.startswith("btn") Then
msgbox(cntrl.name)
End If
End Sub
You can make this even more complex by adding parameters for stuff like controlling recursion and such. Keep in mind that if you want to do any control type-specific stuff with it (ie. anything that is in the control that is not inherited from the Control class), you need to CType that object as the appropriate control. So, if .name was only in the Button class, and did not exist in the Control class, I would have to do the following for this to work:
msgbox(ctype(cntrl, Button).name)
My own personal version of it looks more like this:
Private Sub clearcontrols(ByVal root As Control, ByVal ClearLists As Boolean, Optional ByVal ClearTabPages As Boolean = False)
For Each cntrl As Control In root.Controls
clearcontrols(cntrl, ClearLists, ClearTabPages)
If TypeOf cntrl Is TextBox Then
CType(cntrl, TextBox).Clear()
End If
If TypeOf cntrl Is DataGridView Then
CType(cntrl, DataGridView).Rows.Clear()
End If
If TypeOf cntrl Is ListBox And ClearLists = True Then
CType(cntrl, ListBox).Items.Clear()
End If
If TypeOf cntrl Is TabControl And ClearTabPages = True Then
For Each tp As TabPage In CType(cntrl, TabControl).TabPages
If DynTPList.Contains(tp.Name) Then
tp.Dispose()
End If
Next
End If
Next
End Sub

How to check if a checkbox is checked when iterating through form controls

I'm trying to set a registry key for every checkbox on a form, but in the following block of code, I'm receiving the error 'Checked' is not a member of 'System.Windows.Forms.Control'
Can somebody please help me find out why I'm getting this error?
' Create the data for the 'Servers' subkey
Dim SingleControl As Control ' Dummy to hold a form control
For Each SingleControl In Me.Controls
If TypeOf SingleControl Is CheckBox Then
Servers.SetValue(SingleControl.Name, SingleControl.Checked) ' Error happening here
End If
Next SingleControl
You should convert your control to a CheckBox before using the Checked property.
You use directly the Control variable and this type (Control) doesn't have a Checked property
Dim SingleControl As Control ' Dummy to hold a form control
For Each SingleControl In Me.Controls
Dim chk as CheckBox = TryCast(SingleControl, CheckBox)
If chk IsNot Nothing Then
Servers.SetValue(chk.Name, chk.Checked)
End If
Next
A better approach could be using Enumerable.OfType
Dim chk As CheckBox
For Each chk In Me.Controls.OfType(Of CheckBox)()
Servers.SetValue(chk.Name, chk.Checked)
Next
this removes the need to convert the generic control to a correct type and test if the conversion was successfully
Try this code,
Dim SingleControl As Control
For Each SingleControl In Me.Controls
If TypeOf SingleControl Is CheckBox Then
'control does not have property called checked, so we have to cast it into a check box.
Servers.SetValue(CType(SingleControl, CheckBox).Name, CType(SingleControl, CheckBox).Checked) End If
Next SingleControl
Checked is a property of the CheckBox class, not its Control parent.
You either have to downcast the Control into a Checkbox in order to access the property Checked or you have to store your checkboxes as a CheckBox collection not a Control collection.
Try this:
For Each SingleControl As Control In Me.Controls
If TypeOf SingleControl Is CheckBox Then
Dim auxChk As CheckBox = CType(SingleControl, CheckBox)
Servers.SetValue(auxChk.Name, auxChk.Checked)
End If
Next SingleControl
Use my extension method to get all controls on the form, including controls inside other containers in the form i.e. panels, groupboxes, etc.
<Extension()> _
Public Function ChildControls(Of T As Control)(ByVal parent As Control) As List(Of T)
Dim result As New ArrayList()
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is T Then result.Add(ctrl)
result.AddRange(ChildControls(Of T)(ctrl))
Next
Return result.ToArray().Select(Of T)(Function(arg1) CType(arg1, T)).ToList()
End Function
Usage:
Me.ChildControls(Of CheckBox). _
ForEach( _
Sub(chk As CheckBox)
Servers.SetValue(chk.Name, chk.Checked)
End Sub)