Remove textbox that added dynamically (VB.Net) - vb.net

I am trying to delete a TextBox control (that added dynamically) in my form through Button_Click event (that I added dynamically too) but I cannot find the exact way to do it. My TextBox will added together with Button control (delete button) when a LinkLabel is clicked. So when added dynamically my textbox.name will be like textbox_1,textbox_2,textbox_3 and along with them is a Button control like btnDel1,btnDel2,btnDel3 (all placed in a Panel control).
My coding goes like this :
Private Sub Button_Click(sender As Object, e As EventArgs)
Dim button As Button = TryCast(sender, Button)
Dim textbox As TextBox = TryCast(sender, TextBox)
'In this case when btnDel1 is clicked, textbox_1 will be removed as well
If button.Name = "btnDel1" Then
PanelOthers.Controls.Remove(button)
End If
End Sub
Button is removed successfully but how do I remove the textbox too? Thanks in advance.

There are a couple ways to do this:
Attach all the relevant controls to the delete button's Tag property.
Create a user control that encapsulates the button and textbox.
Option 1: the Tag property
When you create your controls, add the associated controls to the button's .Tag property:
Dim button As Button = New Button
Dim textbox As TextBox = New TextBox
button.Tag = {textbox}
' Add the button and textbox to the UI surface
Now when the button is clicked you can loop over the associated controls and remove them too:
For Each item As Control In button.Tag
item.Dispose()
Next
button.Dispose()
Option 2: A user control
So isn't a tutorial site.. but you can do your own research on this one.
Here's a place to start: https://msdn.microsoft.com/en-us/library/c316f119%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

Related

Use a virtual Keyboard on focused Textboxes and DataGridView Cells

In my Form I have various Textboxes that I write into with an in Form keyboard I created using Buttons. I have this code in Form.Load, which uses an event handler to determine which Textbox has the Focus:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
End If
Next
Then I use this on each button to write a specific character:
Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
If btnQ.Text = "Q" Then
FocussedTextbox.Text += "Q"
ElseIf btnQ.Text = "q" Then
FocussedTextbox.Text += "q"
End If
End Sub
Up to that point I'm good and everything works as intended. The problem is I also have a DataGridView I want to write into but can't focus on it selected cells as I do on Textboxes.
I tried this:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
Dim DGVC As DataGridView = control
AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
End If
Next
But it just selects my last Textbox.
I declared the variable FocussedTextbox as Control so it's not specific to Textbox but any control.
Any help will be greatly appreciated.
To add text to the current ActiveControl using Buttons, these Button must not steal the focus from the ActiveControl (otherwise they become the ActiveControl).
This way, you can also avoid all those FocusedTextbox = textBox etc. and remove that code.
You just need Buttons that don't have the Selectable attribute set. You can use a Custom Control derived from Button and remove ControlStyles.Selectable in its constructor using the SetStyle method:
Public Class ButtonNoSel
Inherits Button
Public Sub New()
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class
Replace your Buttons with this one (or, well, just set the Style if you're already using Custom Controls).
To replace the existing Buttons with this Custom Control:
Add a new class object to your Project, name it ButtonNoSel, copy all the code above inside the new class to replace the two lines of code you find there.
Build the Project. You can find the ButtonNoSel Control in your ToolBox now. Replace your Buttons with this one.
Or, open up the Form's Designer file and replace (CTRL+H) all System.Windows.Forms.Button() related to the Virtual KeyBoard with ButtonNoSel.
Remove the existing event handlers, these are not needed anymore.
Add the same Click event handler in the Constructor of the class that hosts those Buttons (a Form or whatever else you're using).
You can then remove all those event handlers, one for each control, that you have now; only one event handler is needed for all:
Public Sub New()
InitializeComponent()
For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
Next
End Sub
Of course, you also don't need to add event handlers to any other control, this is all that's required.
Now, you can filter the Control types you want your keyboard to work on, e.g., TextBoxBase Controls (TextBox and RichTextBox), DataGridView, NumericUpDown etc.
Or filter only special cases that need special treatment (e.g., MonthCalendar).
To add the char corresponding to the Button pressed, you can use SendKeys.Send(): it will insert the new char in the current insertion point, so you don't need any other code to store and reset the caret/cursor position as it happens if you set the Text property of a Control.
In this example, I'm checking whether the ActiveControl is a TextBoxBase Control, then just send the char that the clicked Button holds.
If it's a DataGridView, first send F2 to enter Edit Mode, then send the char.
You could also just send a char (so, no filter would be required), but in this case, you'll replace, not add to, the existing value of that Cell.
Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
Dim selectedButton = DirectCast(sender, Control)
Dim keysToSend = String.Empty
If TypeOf ActiveControl Is TextBoxBase Then
keysToSend = selectedButton.Text
ElseIf TypeOf ActiveControl Is DataGridView Then
Dim ctrl = DirectCast(ActiveControl, DataGridView)
If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
SendKeys.Send("{F2}")
keysToSend = selectedButton.Text
Else
' Whatever else
End If
If Not String.IsNullOrEmpty(keysToSend) Then
SendKeys.Send(keysToSend)
End If
End Sub
► Note that {F2} is sent just once: when the Cell enters Edit Mode, the ActiveControl is a DataGridViewTextBoxEditingControl, hence a TextBox Control, handled by the TextBoxBase filter.
This is how it works (using just the code posted here):

Visual Basic Dynamically Create and Erase Controls

I use Visual Basic in Visual Studio 2015 and i am trying when i click on a StripMenu to appear me some TextBoxes and Buttons.
After another click in Stripmenu i want to erase them and add new one.
My problem is in Erase (delete or clear my buttons and textboxes) controls from my surface.
I try to do it use Button.Visible =True (or False) but it's not seems to be really helpful in a big amount of controls.
Private Sub ClassAToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ClassAToolStripMenuItem.Click
Label1.Text = "Sum A class Students: "
Dim btnA As Button = New Button
btnA.Location = New Point(420, 180)
btnA.Name = "Btn1"
btnA.Text = "OK"
btnA.Visible = True
Me.Controls.Add(btnA)
AddHandler btnA.Click, AddressOf button
End Sub
Private Sub button()
'What my Button does.
End Sub
I create dynamically through this code my Button but if i want to go in another Menu option i want to erase this button to add again my new controls (such us new buttons labels etc).
Your declaration is out of scope since you declared it in the menu's click method. You would have to use the Find method to get back the reference to the control you created:
Dim btn = Me.Controls.Find("Btn1", True).FirstOrDefault()
If btn IsNot Nothing Then
btn.Dispose()
End If
If you are trying to replace the contents of a panel with a new "screen" on your menu click, you can try code like this:
While Panel1.Controls.Count > 0
Panel1.Controls(0).Dispose()
End While
Dim newControl As New UserControl1
newControl.Dock = DockStyle.Fill
Panel1.Controls.Add(newControl)

Stop items in a list view from being selected on right click

I have a ListView on a Windows Form in VB 2010.
I have set the MultiSelect property of the ListView to False so that only one item can be selected at any time.
I have configured a context menu for the ListView and it shows up correctly when the ListView is right clicked.
[Added a ContextMenuStrip control in the Designer and set the ContextMenuStrip property of the ListView to this.]
Consider these 2 scenarios:
A user right clicks on an item that is already selected in the ListView. Then the context menu is displayed and there are no issues.
A user right clicks on an item other than the item that is already selected in the ListView, Then before the context menu is displayed, the item that the user right clicked is selected.
In scenario 2, I need to stop the item that the user right clicks on from being selected automatically. Need to context menu to be displayed but the item that was previously selected should remain selected.
How can I achieve this?
I noticed that on the ListView's MouseDown event, the SelectedItems.Item(0).Index property is still at the old index. However, on the MouseUp event, this property changes to the new index.
In the MouseDown event handler, or anywhere else, how can I stop the SelectedItems from changing? Or how can I change it back to the previous selected item (without the user noticing it is being changed and then changed back)?
I can catch a right click on the MouseDown or MouseUp using the code below. However, I am not sure what I need to put inside this condition to stop the SelectedItems from changing.
If e.Button = Windows.Forms.MouseButtons.Right Then
...
End If
Note: I am able to use the following code for this. However, when I use this with scenario (2), it selects the item that the user right clicked on and then changes it back to the previous item and this change back is seen by the user. Therefore this solution cannot be used.
Dim intPrevSelectedIndex As Integer = -1
Dim boolCancel As Boolean = False
Private Sub ListView1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDown
If ListView1.SelectedItems.Count > 0 AndAlso e.Button = Windows.Forms.MouseButtons.Right Then
boolCancel = True
intPrevSelectedIndex = ListView1.SelectedItems(0).Index
End If
End Sub
Private Sub ListView1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseUp
If boolCancel Then
lstWalkResults.Items(intPrevSelectedIndex).Selected = True
boolCancel = False
End If
End Sub
Please let me know any solutions you might have. Thanks for your time!
In the code behind you should be able to handle the right click event. In that method you would display the context menu manually and then ignore the click event preventing the item from being selected.
If e.Button = Windows.Forms.MouseButtons.Right Then
//display context menu because you're handling the click event manually.
...context menu code...
Dim ee As New System.Windows.Forms.MouseEventArgs(Forms.MouseButtons.None, e.Clicks, e.X, e.Y, e.Delta)
e = ee
End If

passing variable into contextmenustrip

winforms app with 5 labels.
Each label is a variable pulled from an XML file.
I would like a right-click event to pull data into a contextmenustrip.
Right now I have it half successful. I can copy the url with a right click:
Private Sub Label1_Click(sender As Object, e As MouseEventArgs) Handles Label1.MouseClick
Dim x As String = Label1.Text
If e.Button = Windows.Forms.MouseButtons.Right Then
Dim var As String = xmlinteraction.returnLink(x)
Clipboard.SetText(var, TextDataFormat.Text)
ElseIf e.Button = Windows.Forms.MouseButtons.Left Then
xmlinteraction.appCall(x)
End If
End Sub
I would much prefer the user be prompted to see if they want to copy to clipboard, and if I can make that work I have three other menu item ideas I can easily use.
Can I could pass the copied variable into the first menu item of a contextmenustrip. So then I could create one contextmenustrip for all 5 labels and depending which label you right-click, it gives the correct value if you right-click then "Copy Link" from the contextmenustrip?
You don't need to have a separate ContentMenuStrip for each label. You can apply the one ContextMenuStrip to every label. Once you've done that you can easily determine which control it was that opened the menu from the menu's Opening event or from the Click event of the ToolStripMenuItem
For example: if you were in the Opening event and wanted to find out which Label was right-clicked on so that you could add different menu items you just need to cast the ContextMenuStrip.SourceControl property:
Label clickedLabel = (Label)contextMenuStrip.SourceControl;
Once you're in the Click event and you want to find out which Label was right-clicked on you can just do it like this:
ContextMenuStrip contextMenu = (ContextMenuStrip)((ToolStripMenuItem)sender).Owner;
Label clickedLabel = (Label)contextMenu.SourceControl;

Change a checkbox text and function based on checkbox.checkstate in groupbox

I'm trying to teach myself VB .net and as my first project I'm trying to design a form that functions much like the checkboxes in Gmail. Tons of checkboxes in a group and one checkbox that sits outside the group to select/deselect those within.
I've gotten far enough to have that master checkbox do its thing, but I would really like to have the form notice whenever anything within the groupbox is checked by the user, then to change its text & function automatically. The code I came up with to change the text works, but I can't figure out where to put it:
For Each ctrl As CheckBox In GroupBox1.Controls
If ctrl.CheckState = 1 Then
CheckBox1.Text = "Deselect All"
End If
Next
I can link the code to a button push or a checkbox change, but I'd like it to be automatic since having the user click something to run the check defeats the purpose. I tried double clicking the groupbox and placing the code there but it does nothing. Also tried double clicking the form background but it does nothing there either. Please help.
As you have probably noticed, there may be a few different places where you need to do this. To reuse a piece of functionality, create a new method that does that job. Double-click the form, and place this just before the End Class:
''' <summary>Update each of the CheckBoxes that in the same GroupBox</summary>
''' <param name="sender">The CheckBox that was clicked.</param>
''' <param name="e"></param>
''' <remarks>It is assumed that only checkboxed that live in a GroupBox will use this method.</remarks>
Public Sub UpdateCheckBoxState(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Get the group box that the clicked checkbox lives in
Dim parentGroupBox As System.Windows.Forms.GroupBox = DirectCast(DirectCast(sender, System.Windows.Forms.CheckBox).Parent, System.Windows.Forms.GroupBox)
For Each ctrl As System.Windows.Forms.Control In parentGroupBox.Controls
'Only process the checkboxes (in case there's other stuff in the GroupBox as well)
If TypeOf ctrl Is System.Windows.Forms.CheckBox Then
'This control is a checkbox. Let's remember that to make it easier.
Dim chkBox As System.Windows.Forms.CheckBox = DirectCast(ctrl, System.Windows.Forms.CheckBox)
If chkBox.CheckState = 1 Then
chkBox.Text = "Deselect All"
Else
chkBox.Text = "Select All"
End If
End If ' - is CheckBox
Next ctrl
End Sub
Now you have a method that will do what you want, you need to connect it to each CheckBox that you want to manage. Do this by adding the following code in The Form_Load event:
AddHandler CheckBox1.CheckedChanged, AddressOf UpdateCheckBoxState
AddHandler CheckBox2.CheckedChanged, AddressOf UpdateCheckBoxState
...
So now the same method will handle the ClickChanged method of all of your connected checkboxes.
You can also update the checkBoxes in addition to when the user clicks it by calling the Method UpdateCheckBoxState(CheckBoxThatYouWantToProgramaticallyUpdate, Nothing) perhaps in Form_Load, or elsewhere.