Vb.net + AutoComplete in textboxes - vb.net

So I was reading a bit on AutoComplete of textboxes in VB.NET, but I can't really understand where these are stored? Is it a fully built in feature, or do I have to write some code for it to work? I've found the AutoCompleteMode and AutoCompleteSource properties of textboxes. But I want to append whatever I've written in the textbox to the autocomplete source. Do I connect the source to My.Settings or something? Wouldn't I have to use an array as well? Any help would be appreciated :)

You would have to add new entries to your auto-complete data source manually... which makes sense, when you think about it: How is Windows Forms supposed to know when a new entry should be added to the list of suggestions and when the text entered is only something temporary?
You could add new values e.g. when validation of the input field happens, or when the user presses an OK / Apply button, or whatever fits your need best. But you will have to do this yourself.
The properties you've already discovered are the right ones.
Dim suggestions As New List(Of String)
suggestions.Add("Abba")
suggestions.Add("Nirvana")
suggestions.Add("Rolling Stones")
...
textBox.AutoCompleteSource = suggestions
You can bind AutoCompleteSource to almost anything; this is very similar to data-binding. One thing to keep in mind is that if you're adding new entries to the auto-complete data source, the UI control might not immediately notice if your data source doesn't implement the INotifyCollectionChanged interface.

first create the list to use as the custom source.
Dim MySource As New AutoCompleteStringCollection()
and then set the property of the textbox
With MyTextbox
.AutoCompleteCustomSource = MySource
.AutoCompleteMode = AutoCompleteMode.SuggestAppend
.AutoCompleteSource = AutoCompleteSource.CustomSource
End With
put this code in eventlistener you use for validating the input field, e.g. btnOK.Click
Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
MySource.Add(txtinput.text)
End Sub

Related

Visual Basic, Listbox, is it possible to check if an item gets unselected

I want when the user using the program selects something in the list box, and then selects something else, between that action i want the program to do something, I hope it's clear what I mean.
Thanks in advance.
You would have to handle the SelectedIndexChanged event or the like and then remember the previous item yourself, e.g.
Dim previousSelectedIndex As Integer = -1
Private Sub ListBox1_SelectedIndexChanged(...) Handles ListBox1.SelectedIndexChanged
If previousSelectedIndex <> -1 Then
'Use previousSelectedIndex here.
End If
previousSelectedIndex = ListBox1.SelectedIndex
End Sub
If you wanted to, you could create your own derived class inheriting ListBox and build that functionality into it.

Needing Assistance with vb.NET Application

I don't normally post on forums because I try to find information for myself, and ask as an absolute last resort. I've tried scouring the net for answers, but I'm only receiving about half of the answer I'm looking for.
I'm currently building an application that deals with state law. There's one combo box and one text box. One for the offense title, and one for the numerical code for that particular code section. So say if I select "Kidnapping", it prepopulates the text box below it with "11-5-77", for example.
The method I've been using for, oh, about the last hour now, is:
If AWOffenseTitle.Text = "Kidnapping" Then
AWCN.Text = "11-5-77"
ElseIf AWOffenseTitle.Text = "False Imprisonment" Then
AWCN.Text = "11-5-78"
With AWOffenseTitle being the combo box name, and AWCN being the text box name. While this has proved to work perfectly well so far, I'm sure you can imagine with hundreds of offense titles, this is going to take a ridiculously long time. Well, I finally found a spreadsheet with offense titles and their respective title codes. What I'm looking to do is create two text files within a folder in the local directory "Offenses". One with a vertical list of offenses, and one with a vertical list of offense code numbers that populate the same lines in each. What I'm looking to do is populate the combo box with the contents of text file one (which I can do already), but then selecting an offense title will read the second text file and display it's proper title code. That's what has me at a loss. I'm relatively well-versed with vb.NET, but I'm not an expert by any means.
I'm hoping someone here will be able to provide a code example and explain it to me line-by-line so I can gain a better understanding. I want to get more proficient with VB although it's not so popular anymore. I've been using VB since 6.0, but not on a regular basis. More on a sporadic project kind of basis.
I really appreciate any assistance anyone might be able to provide, and if you need more information, I'd be glad to answer any questions. I tried to be as thorough as I could.
Thank you in advance!
First, you need to retrieve your data. I demonstrated using an Sql Server database containing a table named Offenses with columns named OffenseTitle and OffenseCode. You will have to change this code to match your situation.
Private Function GetOffenseData() As DataTable
Dim dt As New DataTable
Using cn As New SqlConnection("Your connection string"),
cmd As New SqlCommand("Select OffenseTitle, OffenseCode From Offenses;")
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
As the Form loads, set the properties of the ComboBox. DisplayMember matches the name of the title column and ValueMember is the name of the code column.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = GetOffenseData()
ComboBox1.DisplayMember = "OffenseTitle"
ComboBox1.ValueMember = "OffenseCode"
ComboBox1.DataSource = dt
End Sub
Then when the selected item in the combo changes, just set the .Text property of TextBox to the SelectedValue in the combo and your code appears.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
TextBox1.Text = ComboBox1.SelectedValue.ToString
End Sub
There are other ways to do this if your data source is other than a database. Please advise if you need additional help.
In addition to HardCode's comment and Mary's detailed answer, I can only add an answer that's somewhere in between them.
It might be the case, that the information is not taken from a database, but from another source, like a text/data file or a web service. So it might be useful to create an abstraction for the data source you actually use.
First, I create a class or struct that will hold the data for each combo box item.
Class Offense
Public ReadOnly Property Title As String
Public ReadOnly Property Code As String
Public Sub New(title As String, code As String)
Me.Title = title
Me.Code = code
End Sub
End Class
Next, you need a method that retrieves a list of offenses that you can bind to your combo box. It's entirely up to you how you fill/fetch the offenses list. I have simply hard coded your two values here.
Private Function GetOffenseData() As List(Of Offense)
Dim offenses As New List(Of Offense)
offenses.Add(New Offense("Kidnapping", "11-5-77"))
offenses.Add(New Offense("False Imprisonment", "11-5-78"))
Return offenses
End Function
At a certain moment (probably in your form's Load event handler), you need to initialize your combo box. Just like Mary did, I use data binding.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AWOffenseTitle.DropDownStyle = ComboBoxStyle.DropDownList
AWCN.ReadOnly = True
AWOffenseTitle.DisplayMember = NameOf(Offense.Title)
AWOffenseTitle.ValueMember = NameOf(Offense.Code)
AWOffenseTitle.DataSource = GetOffenseData()
End Sub
Note that I use the NameOf operator to get the desired property names of the Offense class. If you ever decide to rename the properties of your Offense class, you will be able to easily detect where they are used, since the compiler will complain if your code still uses the wrong property names somewhere.
Finally, the app needs to react to combo box value changes, so that the text box will show the corresponding offense code. Mary used an event handler for the SelectionChangeCommitted event, but I use a handler for the SelectedIndexChanged event instead:
Private Sub AWOffenseTitle_SelectedIndexChanged(sender As Object, e As EventArgs) Handles AWOffenseTitle.SelectedIndexChanged
AWCN.Text = AWOffenseTitle.SelectedValue
End Sub
(Up to now, I was not aware of the SelectionChangeCommitted event of the ComboBox control. I will need to look into this event to see if it is actually a better choice for this scenario, but I found that the SelectedIndexChanged event does the job just fine, so for now I sticked with that event, since I am more familiar with it.)

VB.NET Check for keydown on dragdrop

I've tried searching quite a bit for this answer but haven't been able to find a good solution.
I have a datagridview on my form where users can drag and drop files onto the grid and certain columns are filled in. This works fine.
I want to be able to check if a user has a certain key pressed at the time the file is dropped. If so, I want to use that to add specific data to one of the columns in the datagrid.
Is this possible?
EDIT:
I have used keydown outside of dragdrop before but it seems that I'm missing something. The code I have is below. No matter what I do, I never get "T is pressed" but I always get "T is not pressed".
Private Sub frmReader_DragDrop(sender As Object, e As DragEventArgs) Handles Me.DragDrop
Dim files As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())
If Keyboard.IsKeyDown(Keys.T) Then
MsgBox("T is pressed.")
' Put certain info into the datagridview
Else
MsgBox("T is not pressed.")
' Put other data into the datagridview
End If
End Sub
God, embarassing... I changed "Keys.T" to "Key.T" and it's working fine. Sorry for the bother.

Faux Databinding a Recordset to a Datagridview

I am updating a very old vb6 program that includes recordsets bound to an old third party grid control. The recordset functionality is so ingrained into the program that it is not an option to replace them. So, I replaced the unfunctional grid with a datagridview and I fill it using a dataadapter and a dataset. The problem is that the recordset was originally bound to the grid and using a dgv breaks the binding.
So this is what I am trying to do. I have a function that passes in the old recordset and the new dgv, and fills it. I would like to create a dynamic handler to the dgv's selectionchanged event to update the rs with the current position on the dgv (rs.aboluteposition = dgv.row), thus updating the rs cursor to the current position in the dgv, making a sort of faux data binding.
Something like this....
AddHandler dgv.SelectionChanged, AddressOf RefreshRecordset
Public Sub RefreshRecordset()
myRS.AbsolutePosition = dgv.Row
End Sub
A couple things though. I have to track if the event handler was already created, and the associated recordset that goes with this specific datagridview. Also, since this is a global function to update many dgvs with many rs, it needs to have a way to track the recordset. I was thinking of somehow using the tag of dgv? Maybe create a dictionary of all the recordsets then look it up by the name of the dgv?
Below is my original method that worked pretty well. I eventually refined it and put it in a class for each recordset. I also updated it to accept true dbgrids. By wrapping it in a class, I was able to remove the dictionaries. In the New function, I pass in either grid and a recordset. From there, I set up event handlers to handle both the grid row change and also the recordset MoveComplete event. I had to use the MoveComplete because the RecordsetChangeComplete has a bug and doesn't always fire correctly. I just check in the MoveComplete if the record count had changed. If so, refresh the grid. Lastly, I added a removehandler for each of the events in the finalize function.
////// The Original Answer //////
For instance, like this... (I CAN'T believe this worked...)
Public dict as new Dictionary(Of String, ADODB.Recordset)
Public Sub FillGrid(ByRef dgv as DataGridView, ByRef rs as ADODB.RecordSet)
'.... Fill the grid with the tableadapter, blah blah.
If Not dict.ContainsValue(rs) Then
dict.add(dgv.Name, rs)
AddHandler dgv.SelectionChanged, AddressOf RefreshRecordset)
' To make the event fire correctly, I think
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End if
End Sub
Public Sub RefreshRecordset(sender As Object, e As System.EventArgs)
Dim dgv as DataGridView = Ctype(sender, DataGridView)
If dict.ContainsKey(dgv.Name) then
Dim rs as ADODB.Recordset = dict(dgv.Name)
rs.AbsolutePosition = dgv.CurrentCell.RowIndex
End if
End Sub
Now I need to create a handler to the recordset to refresh the dgv everytime the recordset is updated.
And btw, I know there are probably other ways to do this and I would absolutely would love to hear them! Please feel free!
Thanks!

Need some advice on putting data into DataGridView in vb.Net

I need a little advice in manipulating DataGridView in Visual Basic .Net. This is my first time playing with DataGridView. My program is to load a .txt file containing data of every room in a building and display them in the DataGridView.
Here is a portion of the file showing 2 rooms:
1;1812;1812;F18;T1;26808.16;.00;.00;.00;.00;.00;.00;
1;1813;1813;F18;T1;24000.00;3500.00;.00;300.00;.00;.00;.00
A room is a one-line string that ends with an endline character.
I have no problem with loading the file and getting all these information. I store data of each room into an object of class Room, and put them in a list.
Right now, I put all of the properties of the room into the data grid's columns like this:
Now, how can I put all these rooms' data into the grid? I tried follow http://www.dotnetperls.com/datagridview-vbnet at first, but setting DataSource to a list of class Room imitating from the given link doesn't show anything in the grid view. How can we tell the program to link rows of the grid to a list of objects? Or am I doing it wrong?
So any advise is appreciated. How do we do this?
I think you'll be pleasantly surprised at how easy this is to do with BindingSources and Visual Studio.
Create your Room Class (already done I presume)
Build your project
Set your Class as your DGV's DataSource:
Click the DGV's smart tag (or the DataSource field in the DGV's property sheet) and on the 'Choose Data Source' pulldown select 'Add Project Data Source...'
On the 'Data Source Config Wizard' select Object and click Next
Navigate your assembly's class structure to select the Class you created in step 1 and click Next
Click Finish to close the Wizard
You'll notice that a new BindingSource has been added to your project. You'll use this BindingSource to bind your List of Room objects to your DGV. Your code will look something like this after you fill your List of Rooms:
roomBindingSource.DataSource = roomList
Note that you'll start with a DataGridView with no columns. After you follow the steps above your DGV will be populated with columns based on the accessibility of the fields in the class you're binding to. At this point you can customize the appearance of the columns such as including removing/adding, etc.
Your problem is that you are using the designer to create your columns and then not linking the DataSource properties to these columns.
The link you posted is talking about automatically generating columns based upon the DataSource which is a list of objects, in that link they do not create the columns in the designer, but instead rely upon the AutoGenerateColumns property being set to true for the DataGridView.
There is a forum post here which talks about what you need to do. It is also described quite well on MSDN.
Basically you need to set the DataPropertyName for each column to match the desired property from your object.
So if your object looks like:
class Room
{
public string RoomName() {get; set;}
}
You need to set the DataPropertyName property to RoomName for the room name column in the grid designer.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' Uses Test class from above.
Dim list = New List(Of Test)
list.Add(New Test("Mac", 2200))
list.Add(New Test("PC", 1100))
DataGridView1.DataSource = list
End Sub
Private Sub DataGridView1_SelectionChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles DataGridView1.SelectionChanged
' Get the current cell location.
Dim y As Integer = DataGridView1.CurrentCellAddress.Y
Dim x As Integer = DataGridView1.CurrentCellAddress.X
' Write coordinates to console.
Console.WriteLine(y.ToString + " " + x.ToString)
End Sub
End Class