ComboBox's SelectedIndexChanged event not being called on Enter - vb.net

I'm working on VS 2010 with VB using .NET Framework 4.0
I have a combobox. It has some items in it and displays just fine. Here's where it gets a little weird:
If I click the drop-down arrow on the combobox and CLICK on the item I want, SelectedIndexChanged is called - good.
If I click inside the text area of the combobox and start typing what I want selected and finish it by pressing the up (or down) key, SelectedIndexChanged is called - also good.
If I click the drop-down arrow on the combobox and start typing what I want selected and finish it by pressing ENTER, SelectedIndexChanged is not called - PROBLEM.
Is there a different event that is caused by the ENTER in the last case? I've tried using the TextChanged and TextUpdate events, but those do not seem to be working:
Private Sub cmbStatus_TextChanged(sender As System.Object, e As System.EventArgs) Handles cmbStatus.TextChanged
If e.Equals(Keys.Enter) Then
Call SomeMethod()
End If
Should I use something besides e.Equals(Keys.Enter)?
Is there another event I should be looking for?
EDIT:
An example of the items in the ComboBox are:
10 - NEW ENTRY AND COMPLETENESS CHECK ---> this is the most common type
13 - ASSIGNED TO TRB/HRB ---> there are a few with '/'
60 - EXTERNAL (HOLD UNTIL FURTHER NOTICE) ---> there are a few with '(' and ')'
Basically, the type of each listing is "## - SOME TEXT".

Disclaimer: this is written in C# - let me know if you need it translated to VB.
private void comboBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
//It's important to also check that the Combo Box is displaying its Drop Down. If
//you want this to execute even when it is not displayed, remove the check for
//comboBox1.DroppedDown.
if (e.KeyCode == Keys.Enter && comboBox1.DroppedDown &&
!string.IsNullOrEmpty(comboBox1.Text))
{
int index;
//Attempt to locate the string typed in by the user. An index of -1
//means it was not found.
if ((index = comboBox1.FindStringExact(comboBox1.Text)) != -1)
{
//Update the SelectedIndex.
comboBox1.SelectedIndex = index;
}
}
}
Interestingly, the docs say that we should be using the SelectionChangeCommitted event instead of the SelectedIndexChanged event when handling selection changes made by the user. It is necessary to do so in this case as the SelectedIndexChanged event fires twice using my approach.
Edit:
To prevent the user from having to type the entire string, use the advice from Adi's answer: go to the properties of the combo box and set set AutoCompleteMode to SuggestAppend and AutoCompleteSource to ListItems - I actully used these settings when creating my answer, so it should work for you.

Option Strict On
Public Class Form1
Friend WithEvents ComboBox1 As New ComboBox With {.Parent = Me}
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
ComboBox1.Items.AddRange({"hello", "tes1ted", "word", "item", "tes2ted"})
ComboBox1.Text = ComboBox1.Items(0).ToString
End Sub
Private Sub ComboBox1_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) Handles ComboBox1.KeyUp
'You can put this in the keydown event, or adapt it a small bit and put it in the keypress event
'putting it in the textchanged event is problematic and not recommended.
Dim OriginalText As String = ComboBox1.Text
If e.KeyCode = Keys.Enter Then
If ComboBox1.SelectionLength > 0 Then
ComboBox1.Text = ComboBox1.Text
ComboBox1.SelectionLength = 0
ComboBox1.SelectionStart = ComboBox1.Text.Length
End If
End If
If Not IsTextKey(e.KeyCode) Then Exit Sub
Dim Filter As String = ComboBox1.Text & "*"
If Filter.Length = 1 Then Exit Sub
For I = 0 To ComboBox1.Items.Count - 1
If LCase(ComboBox1.Items(I).ToString) Like LCase(Filter) Then
ComboBox1.SelectedItem = ComboBox1.Items(I)
ComboBox1.Select(OriginalText.Length, (ComboBox1.Text.Length - OriginalText.Length))
Exit Sub
End If
Next
End Sub
Function IsTextKey(ByVal Key As Integer) As Boolean
Select Case True
Case Key = Keys.Up : Return False
Case Key = Keys.Down : Return False
Case Key = Keys.Left : Return False
Case Key = Keys.Right : Return False
Case Key = Keys.Back : Return False
Case Key = Keys.Delete : Return False
Case Key = Keys.LWin : Return False
Case Key = Keys.RWin : Return False
'add whatever I missed
'return false if the key either removes text from the textbox
'or does not produce a character
Case Else
'return true if the key produces a visible character(including space)
Return True
End Select
End Function
End Class

Private Sub ComboBox1_KeyUp(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyUp
If e.KeyCode = Keys.Enter Then
MessageBox.Show(ComboBox1.SelectedText)
Call SomeMethod()
End If
End Sub

I believe that you should set AutoCompleteMode to SuggestAppend and AutoCompleteSource to ListItems. This way, if what you type in is sustainable with the items loaded in the ComboBox, by writing it down and finding that item, when pressed Enter, the SelectedIndexChanged will be fired (even if a match wouldn't be found - the first in the list will be selected)
I've prepared something to point out this to you.
Regards,
Adi Konstantin

Subscribe to the KeyPressed event:
Private Sub yourComboBox_KeyPressed(sender As System.Object, e As System.KeyPressedEventArgs) Handles yourComboBox.KeyPressed
If e.KeyChar.Equals((char)Keys.Enter) Then
Call SomeMethod()
End If

this will helps your problems
Private Sub ComboBox1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyDown
If e.KeyCode = Keys.Enter Then
MsgBox("hello")'call some functions
End If
End Sub

Can you let me know if this works for you?
Private Sub ComboBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles ComboBox1.KeyPress
If e.KeyChar = Chr(13) Then
ComboBox1_SelectedIndexChanged(sender, e)
End If
End Sub
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
MsgBox(ComboBox1.Text)
'Your code here
End Sub

I had a similar problem when the combobox dropdownstyle was set to simple with autocomplete set to append, sourcing from my listitems. My workaround was to have a string variable save the combobox text upon each textchanged event. That way, when ENTER is pressed, you can retrieve the deleted text and reassign it to the combobox text.
'Global declaration
'Global declaraion
dim selected_text as string = ""
Private Sub combobox_textchanged(sender As Object, e As EventArgs) Handles combobox.TextChanged
If combobox.Text IsNot Nothing And combobox.Text <> "" Then
selected_text = combobox.Text
End If
End Sub
Private Sub combobox_keydown(sender As Object, e As KeyEventArgs) Handles combobox.KeyDown
If e.KeyCode = Keys.Enter Then
combobox.Text = selected_text
'put logic here
End If
End Sub
There are some great answers above, but I liked that I didn't need to sort out all the command keys and arrows etc.

Close the list manualy on PreviewKeyDown event:
Private Sub cmbStatus_PreviewKeyDown(sender As ComboBox, e As PreviewKeyDownEventArgs) Handles cmbStatus.PreviewKeyDown
If e.KeyCode = Keys.Enter Then sender.DroppedDown = False
End Sub

Related

Detect when a user stops editing a DataGridViewCell

I am working on a VB.Net project and am trying to set up a DataGridView so that users can edit data. I'd like to set it up so that when a user finishes editing a cell, either through navigating to a new cell, or by pressing the Enter key, something happens.
I started by creating a method to store the old data that was in the cell:
Private oldCellVal As String = ""
Private oldCellRow As Integer
Private oldCellCol As Integer
Private Sub dg_CellBeginEdit(ByVal sender As Object, ByVal e As DataGridViewCellCancelEventArgs) Handles dg.CellEndEdit
oldCellVal = dg.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
oldCellRow = e.RowIndex
oldCellCol = e.ColumnIndex
End Sub
Now my next logical step was to create a KeyDown event for the DataGridView
Private Sub dg_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles dg.KeyDown
If e.KeyCode <> Keys.Enter Then
If dg.IsCurrentCellInEditMode() Then
If MessageBox.Show("Would you like to cancel editing?", "Confirmation", MessageBoxButtons.YesNoCancel) = DialogResult.Yes Then dg.CurrentCell.Value = oldCellVal
End If
ElseIf e.KeyCode = Keys.Enter Then
If MessageBox.Show("Would you like to save these changes?", "Confirmation", MessageBoxButtons.YesNoCancel) = DialogResult.Yes Then MessageBox.Show("Saved")
End If
End Sub
Well here we have our first problem. While the DataGridView is in edit mode for a cell, it does not register KeyDown events. No matter what I did, I could not trigger the KeyDown event handler until after moving to another cell. Essentially I need to hit Enter twice in order for the MessageBox to appear.
So from here I figured, okay, lets put together an event handler for EditingControlsShowing that should work!
Private Sub dg_EditingControlsSHow(ByVal sender As Object, ByVal e As DataGridViewEditingControlShowingEventArgs) Handles dg.EditingControlShowing
MessageBox.Show("Please work")
End Sub
And here the MessageBox only appears once the editting has begun, and I can do nothing once I am finished.
So I am utterly confused as to what to do here. To restate what I want to do I am trying to set up a DataGridView that has the following functionality for the Cells:
While editing the value within a Cell, if you press the Enter key, you get a prompt asking if you want to save your changes.
If instead of Enter, you press any other key that would turn off Cell editing (like Tab or the Arrow Keys) you get a prompt asking if you are sure you wish to cancel editing.
I really don't know what to do here, so any and all help is greatly appreciated.
First you need to check if you are in edit mode:
Private isEditing As Boolean = False
Private Sub DataGridView1_CellBeginEdit(sender As Object, e As DataGridViewCellCancelEventArgs) Handles DataGridView1.CellBeginEdit
isEditing = True
End Sub
Private Sub DataGridView1_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
isEditing = False
End Sub
Then you can override the ProcessCmdKey function:
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
If isEditing = True Then
Select Case keyData
Case Keys.Left
Case Keys.Right
Case Keys.Enter
Case Else
End Select
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Return True from the function if you want to suppress the key.

Is there a way of having a textbox with "A. " locked in however you can still type in after this? [duplicate]

This question already has answers here:
How to set the first few characters of a WinForms TextBox to Read-Only?
(11 answers)
Closed 6 years ago.
I need to have a textbox which a user can type into however they cannot edit some words in the textbox. I know I could use a label or two textboxes with one locked however id prefer to only have one, is this possible?
If "A." will always be the 2 first characters of your textBox, then you can use the TextBox.KeyPress event :
Private Sub TextBox2_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox2.KeyPress
' Get the current index of your cursor in the textBox
Dim index As Integer = TextBox.SelectionStart
If index <= 2 Then
If e.KeyChar = ControlChars.Back Then
' Cancel the deletion
e.Handled = True
End If
End If
End Sub
This is the same principle for the "suppress" key.
You can prevent the user to paste on the TextBox or select all the text, etc...
You can initialize the TextBox with "A." with the code TextBox.Text = "A."
This solution seems to work well. You can define any 'prefix' text you want into a string var or const, initialize the textbox text in form_load and include the below code in the TextBox's KeyDown event.
The Keydown code protects the 'prefix' text by suppressing backspacing/deleting of the prefix text, as well as preventing typed text from starting within the prefix text by checking and modifying the SelectionStart property. Effectively it 'pushes' typed or selected text past the prefix text if the insertion point or selection start is within the prefix text.
Public Class Form1
Const PREFIX As String = "A. "
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.TextBox1.Text = PREFIX
End Sub
Private Sub TextBox1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown
Dim tb As TextBox = DirectCast(sender, TextBox)
If tb.SelectionStart + tb.SelectionLength <= PREFIX.Length And (e.KeyCode = Keys.Back Or e.KeyCode = Keys.Delete) Then e.SuppressKeyPress = True
If tb.SelectionStart <= PREFIX.Length Then tb.SelectionStart = PREFIX.Length
End Sub
End Class
You could also get fancy and sub-class the textbox control to incorporate this logic. You could add a 'Prefix' (string) property and override the OnKeyDown event with the keydown logic.
Another way to get fancy, if you want to avoid placing KeyDown code in every textbox, is to 'decorate' the textbox control once with an external class that implements the keydown logic.
Public Class Form1
Private _tbPrefix As TBPrefix
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
_tbPrefix = New TBPrefix(Me.TextBox1, "A. ")
End Sub
End Class
Public Class TBPrefix
Protected WithEvents _tb As TextBox
Protected _prefix As String
Public Sub New(ByRef TB As TextBox, Prefix As String)
_tb = TB
_prefix = Prefix
If _tb IsNot Nothing Then _tb.Text = _prefix
End Sub
Public Property Prefix As String
Get
Return _prefix
End Get
Set(value As String)
_prefix = value
End Set
End Property
Public ReadOnly Property TextBox As TextBox
Get
Return _tb
End Get
End Property
Protected Sub TextBox1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles _tb.KeyDown
Dim tb As TextBox = DirectCast(sender, TextBox)
If tb.SelectionStart + tb.SelectionLength <= Prefix.Length And (e.KeyCode = Keys.Back Or e.KeyCode = Keys.Delete) Then e.SuppressKeyPress = True
If tb.SelectionStart <= Prefix.Length Then tb.SelectionStart = Prefix.Length
End Sub
End Class
The benefit of this approach is that it avoids the need to subclass and allows the assignment of the prefix label text in one step. It can easily be applied to as many textboxes as needed. It can also be adapted to work with other controls such as comboboxes.
This decorator class provides some 'convenience' properties, the prefix text can be modified via the 'Prefix' property, and the decorated textbox control is exposed through the readonly TextBox property.
If you want to be really efficient, and you are not otherwise using the 'Tag' property of the textbox, you can avoid declaring a class-scoped field for the decorator and instead do this:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.TextBox1.Tag = New TBPrefix(Me.TextBox1, "A. ")
End Sub

How to change the Location (x,y) of the object by using coding in VB.net?

I Want to say sorry if there was a same question like i had. I have tried to Search but i couldn't find it, so.. i hope there is no other question like this..
To the point, i need your help to tell me how to change the Location of an object in a form
What i want to do is making the Button1 move to the left when i press the left key on the keyboard. But i have a problem with how to set the location (x,y) of the object
Private Sub Button1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Button1.KeyPress
If Asc(e.KeyChar) = Keys.Left Then
End If
End Sub
Thanks ...
By default, the arrow keys are not captured by the control's KeyPress, KeyDown or KeyUp events. You can make them be captured by KeyDown and KeyUp by setting e.IsInputKey to True in the PreviewKeyDown event. Then you can move the button sideways by changing its Left property. The following assumes the button has focus.
Private Sub Button1_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) _
Handles Button1.PreviewKeyDown
If e.KeyCode = Keys.Left Or e.KeyCode = Keys.Right Then e.IsInputKey = True
End Sub
Private Sub Button1_KeyDown(sender As Object, e As KeyEventArgs) _
Handles Button1.KeyDown
Dim myButton As Button = CType(sender, Button)
If e.KeyCode = Keys.Left Then myButton.Left -= 1
If e.KeyCode = Keys.Right Then myButton.Left += 1
End Sub
Updated Solution
Here's a way to accomplish it so that it moves while holding down the key. Create a project with a Form and Button.
Right-click on the Project in the Solution Explorer and add two .NET References:
PresentationCore
WindowsBase
Here's the code. A timer will capture key events and move the button:
Imports System.Windows.Input
Public Class Form1
Private timex As New Timer
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
AddHandler timex.Tick, AddressOf myTickEvent
timex.Enabled = True
timex.Interval = 100
End Sub
Private Sub myTickEvent(sender As Object, e As EventArgs)
If isKeyPressed(Key.Left) Then
Me.Button1.Left -= 10
End If
If isKeyPressed(Key.Right) Then
Me.Button1.Left += 10
End If
If isKeyPressed(Key.Up) Then
Me.Button1.Top -= 10
End If
If isKeyPressed(Key.Down) Then
Me.Button1.Top += 10
End If
End Sub
Private Function isKeyPressed(ByRef keys As System.Windows.Input.Key)
If (Windows.Input.Keyboard.GetKeyStates(keys) And Windows.Input.KeyStates.Down) > 0 Then
Return True
Else
Return False
End If
End Function
End Class

vb.net - enable/disable a button depending on user input

As I'm putting the finishing touches on my program I'm having some troubles.
Theres several user inputs and a submit button, once the inputs has been filled I wish to enable the submit button, else the button should be disabled. This is what I have:
Private Sub ButtonControl(sender As System.Object, e As System.EventArgs) Handles Input1.Validated
If Input1.Text = "" Then
ButtonSubmit.Enabled = False
ElseIf Input1.Text <> "" Then
ButtonSubmit.Enabled = True
End If
End Sub
The thing is it disables nomatter what and then it doesnt enable when my input is filed
Your code will work if you have another control that can receive the focus. Control Validation occurs on the loss of focus. If you need to have just one focusable item active you will need to use either KeyPress, KeyDown or Textchanged events to enable your button, also make sure that the CausesValidation property of your TextBox is true.
I would also make the method more generic so you could call it from multiple textbox's by using the sender object to access the textbox that raised the event. Also if you have a True/False condition you only need to do the comparison in the first if statement and then you just use an else not an elseif.
for example:
Private Sub ButtonControl(sender As System.Object, e As System.EventArgs) Handles Input1.Validated
If DirectCast(sender, TextBox).Text = "" Then
ButtonSubmit.Enabled = False
Else
ButtonSubmit.Enabled = True
End If
End Sub
You can also use the String.IsNullOrWhiteSpace Method to check if just spaces have been entered if you are using the 4.0 framework or above. Like this TextChanged EventHandler.
Private Sub ButtonControl(sender As Object, e As EventArgs) Handles Input1.TextChanged
If String.IsNullOrWhiteSpace(DirectCast(sender, TextBox).Text) Then
ButtonSubmit.Enabled = False
Else
ButtonSubmit.Enabled = True
End If
End Sub
You are going to need to use the TextBox "TextChanged" event, and be sure to set each Textbox AutoPostback="True". You can use an UpdatePanel to make the postbacks that occur on each Textbox you wish to validate less obnoxious to your end-user.
So, your textbox (if you have many, make sure they all have the OnTextChanged="ValidateForm":
<asp:TextBox ID="Input1" runat="server" OnTextChanged="Validate_TextChanged" />
Inside your textchanged ("ValidateForm") event (which each Textbox is attached to), one quick to implement route to do would just be
' Validation inside this event
Protected Sub Validate_TextChanged(sender As Object, e As EventArgs)
if Input1.text <> "" AndAlso Input2.text <> "" AndAlso ' ...etc.
End Sub
If you go the route of the UpdatePanel, you may find this useful.
This is the kind of thing I would do:
Private Sub TextBoxes_TextChanged( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles _
TextBox1.TextChanged, _
TextBox2.TextChanged, _
TextBox3.TextChanged
Dim textBoxes = { TextBox1, TextBox2, TextBox3 }
Button1.Enabled = textBoxes.All(Function (tb) tb.Text <> "")
End Sub
You can then add as many text boxes in to the textBoxes array as you need to check. Just make sure that the text boxes to the Handles list.
Private Sub TextBox1_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBox1.TextChanged
If TextBox1.Text.Length > 0 Then
Me.Button1.Enabled = True
Else
Me.Button1.Enabled = False
End If
End Sub
Do that code in the Input1_TextChanged event
This is what I did and worked:
Dim CheckInput1 As Boolean
Private Sub Input1_TextChanged(sender As Object, e As EventArgs) Handles Input1.TextChanged, Input1.Enter
CheckInput1 = True
If Input1.Text = "" Then
CheckInput1 = False
End If
If CheckInput1 = False Then
ButtonSubmit.Enabled = False
ElseIf CheckInput1 = True Then
ButtonSubmit.Enabled = True
End If
End Sub
There must be a more efficient code that this but I think this solves your problem.

Getting value of ListView using up / down keys

I need to store the value of ItemCode at coloumn 0 of my ListView.
Using the following code in click event, it works
vrEditProductCode = lvVendors.SelectedItems.Item(0).SubItems.Item(0).Text
But the same code in selectedindex changed event is causing an index out of range exception.
Please advise how to fix it. I want user to get this value when up/down arrow key is pressed.
In datagridview, we can do it like
vrItemCode=dgvOne.item(0,dgvitem.currentrow.index).value
But I could not do it in list view. Please help.
Thanks
What about this code snippet :
Private Sub ListView1_ItemSelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ListViewItemSelectionChangedEventArgs) Handles ListView1.ItemSelectionChanged
Debug.WriteLine(e.ItemIndex)
Debug.WriteLine(e.Item.Text)
End Sub
This should enable you to record items that have been selected.
I would recommend using the ItemSelectionChanged rather than the IndexChanged because it is more appropriate and easier to use, mainly because you get a more precise EventArg, specifically a System.Windows.Forms.ListViewItemSelectionChangedEventArgs
Because the ListView first deselects the old selection lvVendors.SelectedItems is null.
So you need to check first if SelectedItems != null:
VB.NET:
If lvVendors.SelectedItems IsNot Nothing AndAlso lvVendors.SelectedItems.Count <> 0 Then
Dim vrEditProductCode As String = lvVendors.SelectedItems.Item(0).SubItems.Item(0).Text
End If
C#:
if (lvVendors.SelectedItems != null && lvVendors.SelectedItems.Count!=0)
{
string vrEditProductCode = lvVendors.SelectedItems.Item[0].SubItems.Item[0].Text;
}
Maybe you can use this:
Private Sub lvSearch_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles lvSearch.KeyDown
If e.KeyCode = Keys.Down Then
If lvSearch.SelectedItems(0).Index < (lvSearch.Items.Count - 1) Then
txtName.Text = lvSearch.Items(lvSearch.SelectedItems(0).Index + 1).SubItems(1).Text
End If
End If
End Sub
Private Sub lvSearch_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles lvSearch.KeyUp
If e.KeyCode = Keys.Up Then
If lvSearch.SelectedItems(0).Index >= 0 Then
txtName.Text = lvSearch.Items(lvSearch.SelectedItems(0).Index).SubItems(1).Text
End If
End If
End Sub