Me.Close not working and a Break Mode window appears - vb.net

I have a class where I will get the value of username and password of my login form and pass it to admin form.
Public Property getUsername() As String
Get
Return Login.username.Text
End Get
Set(value As String)
uname = value
End Set
End Property
Public Property getPassword() As String
Get
Return Login.password.Text
End Get
Set(value As String)
pword = value
End Set
End Property
A function getName()
Public Function getName()
con.Open()
Dim sd As New SqlDataAdapter("select * from AdminAcc where Username = '" & getUsername() & "'", con)
Dim dt As New DataTable
sd.Fill(dt)
con.Close()
getName = dt.Rows(0)(1).ToString()
End Function
I want to display the name of that user in my form so I tried this one:
Private Sub AdminM_Load(sender As Object, e As EventArgs) Handles MyBase.Load
admingreeting.Text = "Hi, " + queryclass.getName()
End Sub
It is actually working, but when I try to sign out the application stops and a break mode window appears.
Private Sub btnsignout_Click(sender As Object, e As EventArgs) Handles btnsignout.Click
If MsgBox("Are you sure you want to sign out?", vbQuestion + vbYesNo) = vbYes Then
Login.Show()
Me.Close()
End If
End Sub
I tried using the me.hide() and it worked, but when I tried to login another acc, the value in the previous getName() did not change.

I'm not sure based on what you've said whether this will solve your problem, but try changing the Shutdown Mode:
If you bring up the Properties window for the project, on the Applications Tab you can set the 'Shutdown mode'. The default is when the 'Startup Form Closes'. Change it to 'When the last form closes'.

Related

How to query database for log in form in Visual Studio+Basic?

Trying to learn Visual Studio, I was able to create a static log in form e.g. check if the text box and password match the hard coded data, but I just cannot get the Access query to work. I've ran through 6 different efforts (cleared them all until this point)
Imports System.Data.OleDb
Public Class Login
Dim con As New OleDbConnection
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\someone\source\repos\Test\Test\vs.mdb"
con.Open()
Dim logincmd As New OleDbCommand("Select * From tblLogin WHERE userName = " & tbUser.Text, con)
Dim loginrd As OleDbDataReader = logincmd.ExecuteReader
If (loginrd.Read() = True) Then
MenuPage.Show()
Me.Close()
Else
MsgBox("Sorry that's not right")
End If
End Sub
Error: System.Data.OleDb.OleDbException: 'No value given for one or more required parameters.'
On line: Dim loginrd As OleDbDataReader = logincmd.ExecuteReader
Please tell me where I'm going wrong?
EDIT: I've found some code that works, so I'm going to cross reference the two and try work out why the above code didn't work, might help me get a better understanding of things!
Database objects like Connections and Commands need to be disposed. Using...End Using blocks handle this for us. They both declare and dispose the objects. In this code both the connection and command are handled by a single Using block. Note the comma on the first line of the Using.
You can pass the connection string directly to the constructor of the connection. You can also pass the CommandText and Connection directly to the constructor of the command. A constructor will be indicated by the New keyword.
Always use parameters to help defeat sql injection. Parameters will not be treated as executable code by the database.
Don't open the connection until directly before the Execute statement and close and dispose as soon as possible with End Using.
Since we are only seeking a single piece of data (the count) we can use ExecuteScalar which returns the first column of the first row of the result set.
Private ConnStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\someone\source\repos\Test\Test\vs.mdb"
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
'Validate input
If txtUserName.Text = "" OrElse txtPassword.Text = "" Then
MessageBox.Show("Please fill in both Name and Password.")
Exit Sub
End If
If ValidateLogin(txtUserName.Text, txtPassword.Text) Then
MenuPage.Show()
Me.Close()
Else
MessageBox.Show("Invalid Login")
End If
End Sub
Private Function ValidateLogin(uName As String, pWord As String) As Boolean
Dim IsValid As Boolean
Dim ReturnValue As Integer
Using cn As New OleDbConnection(ConnStr),
cmd As New OleDbCommand("Select Count(*) From tblLogin Where userName = #UserName AND passWord = #Password;", con)
cmd.Parameters.Add("#UserName", OleDbType.VarChar).Value = uName
cmd.Parameters.Add("#Password", OleDbType.VarChar).Value = pWord
cn.Open()
ReturnValue = CInt(cmd.ExecuteScalar)
End Using
If ReturnValue = 1 Then
IsValid = True
End If
Return IsValid
End Function
Of course, you should never store passwords as plain text. Investigate encryption and salting.
I'd suggest
Separating login code from form code
Never use string concatenation for SQL parameters, use command parameters.
Encrypting the database
If exception.Message.ToLower.Contains("not a valid password") Then in this case is for an encrypted database, ignore if not encrypting the database.
Recommend a class for login (table columns shown are different from yours but the logic will work no matter)
Login class
Permits three attempts at a login.
Imports System.Data.OleDb
Public Class ApplicationLogin
Private ReadOnly ConnectionString As String
Public Property UserName As String
Public Property UserPassword As String
Public Property Retries As Integer
Private Userid As Integer
Public ReadOnly Property UserIdentifier As Integer
Get
Return Userid
End Get
End Property
Public Sub New(pConnectionString As String)
ConnectionString = pConnectionString
End Sub
Public Function Login() As Boolean
If Not String.IsNullOrWhiteSpace(Me.UserName) AndAlso Not String.IsNullOrWhiteSpace(Me.UserPassword) Then
Using cn As New OleDbConnection With {.ConnectionString = ConnectionString}
Using cmd As New OleDbCommand With
{
.Connection = cn,
.CommandText =
"SELECT Identifer, UserName, UserPassword FROM Users " &
"WHERE UserName = #UserName AND UserPassword = #UserPassword"
}
cmd.Parameters.Add("#UserName", OleDbType.LongVarChar).Value = UserName
cmd.Parameters.Add("#UserPassword", OleDbType.LongVarChar).Value = UserPassword
Try
cn.Open()
Catch exception As Exception
If exception.Message.ToLower.Contains("not a valid password") Then
Return False
Else
Throw
End If
End Try
Dim reader = cmd.ExecuteScalar
If reader IsNot Nothing Then
Userid = CInt(reader)
Retries = 0
Return True
Else
Retries += 1
Return False
End If
End Using
End Using
Else
Return False
End If
End Function
End Class
Form code
Public Class Form1
Private Retries As Integer = 0
Private Sub LoginButton_Click(sender As Object, e As EventArgs) Handles LoginButton.Click
Dim appLogin As New ApplicationLogin("Your connection string") With
{.UserName = txtUserName.Text, .UserPassword = txtPassword.Text}
If appLogin.Login Then
' login successful
Else
Retries += 1
' too many retries
End If
End Sub
End Class
Full source (not done with .mdb but .accdb)
Front end project
Class project for login logic
Database encryption docs

Removing items in a collection based on listbox string

Having issues when clicking the remove button. If more of my code is needed, let me know. I get this error on the line AddressList.Remove(selectedName):
System.ArgumentException: 'Argument 'Key' is not a valid value.
I've tried many variations but can't figure out why this doesn't work. I think it has something to do with how the strings are concatenated in the listbox. I need to be able to remove entries from the collection and the listbox. Any help would be greatly appreciated.
Module EmailCollection
Public AddressList As New Collection
Public Sub AddRecord(ByVal a As cAddress)
Try
AddressList.Add(a)
Catch ex As Exception
MessageBox.Show("Error: inputs must be characters valid in string format")
End Try
End Sub
End Module
public class form1
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim frmAdd As New AddNewName
frmAdd.ShowDialog()
UpdateListBox()
End Sub
Private Sub UpdateListBox()
lstAddress.Items.Clear()
Dim a As cAddress
For Each a In AddressList
lstAddress.Items.Add(String.Concat(a.strName, a.strEmail, a.strPhone, a.strComment))
Next
If lstAddress.Items.Count > 0 Then
lstAddress.SelectedIndex = 0
End If
End Sub
Private Sub btnRemove_Click(sender As Object, e As EventArgs) Handles btnRemove.Click
Dim selectedName As String
Try
' Get the selected value.
selectedName = lstAddress.SelectedItem.ToString()
' Remove the selected name from the list box and the collection.
If MessageBox.Show("Are you sure?",
"Confirm Deletion",
MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
lstAddress.Items.Remove(selectedName)
AddressList.Remove(selectedName)
End If
Catch ex As NullReferenceException
MessageBox.Show("Select an item to remove.", "Selection Needed")
End Try
End Sub
end class
In your Module I changed AddressList from the old VB6 Collection type to the .net List(Of T). The T stands for Type.
Module EmailCollection
Public AddressList As New List(Of cAddress)
Public Sub AddRecord(ByVal a As cAddress)
AddressList.Add(a)
End Sub
End Module
I guessed that your cAddress class looks something like this. I added a custom .ToString method so the list box will display the data you wish but the item, itself, will be a cAddress object.
Public Class cAddress
Public Property strName As String
Public Property strEmail As String
Public Property strPhone As String
Public Property strComment As String
Public Overrides Function ToString() As String
Return $"{strName}, {strEmail}, {strPhone}, {strComment}"
End Function
End Class
In the Form...
Instead of adding a string to the list box I added the cAddress object. The list box calls .ToString on the object to get the display value.
Private Sub UpdateListBox()
ListBox1.Items.Clear()
For Each a As cAddress In AddressList
ListBox1.Items.Add(a)
Next
If ListBox1.Items.Count > 0 Then
ListBox1.SelectedIndex = 0
End If
End Sub
In the remove button I cast the selected item to its underlying type, cAddress. This is the item removed from the AddressList. Then simply remove the selected item from the list box.
Private Sub btnRemove_Click(sender As Object, e As EventArgs) Handles btnRemove.Click
If MessageBox.Show("Are you sure?",
"Confirm Deletion",
MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
AddressList.Remove(DirectCast(ListBox1.SelectedItem, cAddress))
ListBox1.Items.Remove(ListBox1.SelectedItem)
End If
End Sub
I changed the name of the list box to ListBox1 to match my test project.
Here is something to try, use a BindingSource for setting up the ListBox. In the class override ToString to what is to be shown in the ListBox rather than what you are doing now without a DataSource.
My version of your class has name and property name changes.
Public Class Address
Public Property Name() As String
Public Property Email() As String
Public Property Phone() As String
Public Property Comment() As String
Public Overrides Function ToString() As String
Return $"{Name} {Email} {Phone} {Comment}"
End Function
End Class
Mocked data is used to populate the ListBox
Public Class Form1
Private ReadOnly _bsAddresses As New BindingSource
Private Sub UpdateListBox()
Dim AddressList = New List(Of Address) From
{
New Address() With {
.Name = "John",
.Email = "john#gmail.com",
.Phone = "555-444-3456",
.Comment = "AAA"},
New Address() With {
.Name = "Mary",
.Email = "mary#gmail.com",
.Phone = "888-333-2222",
.Comment = "BBB"},
New Address() With {
.Name = "Bob",
.Email = "bob#gmail.com",
.Phone = "111-555-9999",
.Comment = "CCC"}
}
_bsAddresses.DataSource = AddressList
lstAddress.DataSource = _bsAddresses
lstAddress.SelectedIndex = 0
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) _
Handles Me.Shown
UpdateListBox()
End Sub
Private Sub RemoveButton_Click(sender As Object, e As EventArgs) _
Handles RemoveButton.Click
If lstAddress.Items.Count > 0 AndAlso lstAddress.SelectedItem IsNot Nothing Then
Dim address = CType(_bsAddresses.Current, Address)
If My.Dialogs.Question($"Remove {address.Name}") Then
_bsAddresses.RemoveCurrent()
RemoveButton.Enabled = _bsAddresses.Count > 0
End If
End If
End Sub
End Class
Code module for asking a question
Namespace My
<ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)>
Partial Friend Class _Dialogs
Public Function Question(text As String) As Boolean
Return (MessageBox.Show(
text,
My.Application.Info.Title,
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) = MsgBoxResult.Yes)
End Function
End Class
<HideModuleName()>
Friend Module WinFormsDialogs
Private instance As New ThreadSafeObjectProvider(Of _Dialogs)
ReadOnly Property Dialogs() As _Dialogs
Get
Return instance.GetInstance()
End Get
End Property
End Module
End Namespace
Karen's post seems quite comprehensive. My response is an attempt to focus on your direct question.
I don't see all of the type definitions shown in your code, but in answer to your question, which I believe is "Why am I getting System.ArgumentException: 'Argument 'Key' is not a valid value":
In the offending line of code:
AddressList.Remove(selectedName)
AddressList is a collection. To use .Remove, you must pass in an object of the AddressList collection to remove it. You are passing a simple string, and that is not an AddressList object. You need to create an object based on your string selectedName to pass into .Remove and that line should work. The rest of what you are doing seems more complex.

Login Form - Not working

Struggling with creating a login from a text file database. The information needs to be manually entered into the text file before it works... see my code below for the form. Its not letting me login.
Public Class UserLogin
Private PWD As String
Public User As User
Public Users As List(Of User) = New List(Of User)
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.Close()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
If isValidData() Then
If isValidUser() Then
MessageBox.Show("Login Successful")
Form2.Show()
Me.Hide()
Else
MessageBox.Show("Incorrect Username or password")
End If
End If
Catch ex As Exception
MessageBox.Show(ex.Message & vbCrLf & vbCrLf & ex.GetType.ToString & vbCrLf & vbCrLf & ex.StackTrace, "User Does not Exist")
End Try
End Sub
Private Function isValidData() As Boolean
Return Validator.IsPresent(TextBox1, "Username") AndAlso
Validator.IsPresent(TextBox2, "Password")
End Function
Private Function isValidUser() As Boolean
Return UserDB.ValidateUser("Username", "Password")
End Function
Public Sub setPath(cwd As String)
PWD = cwd
End Sub
End Class
User class below :
Public Class User
Public Sub New()
End Sub
Public Sub New(Username As String, Password As String)
Me.Username = Username
Me.Password = Password
End Sub
Public Property Username As String
Public Property Password As String
Public Function GetDisplayText(sep As String) As String
Dim text As String = Username & sep & Password
Return text
End Function
End Class
UserDB class Below
Imports System.IO
Public Class UserDB
Private Const Databasename = "C:\Depreciate\Users.txt"
Public User As New User
Public Shared Users As List(Of User) = New List(Of User)
Public Shared Function GetUsers(Dir As String) As List(Of User)
Dim Users As New List(Of User)
Dim textIn As New StreamReader(
New FileStream(Databasename, FileMode.OpenOrCreate, FileAccess.Read))
Do While textIn.Peek <> -1
Dim row As String = textIn.ReadLine
Dim columns As String() = row.Split(CChar(","))
Dim User As New User
User.Username = columns(0)
User.Password = columns(1)
Users.Add(User)
Loop
textIn.Close()
Return Users
End Function
Public Shared Function ValidateUser(username As String, password As String) As Boolean
Dim Validated = False
For Each userEntry As User In Users
If username = userEntry.Username AndAlso password = userEntry.Password Then
Validated = True
Exit For
End If
Next
Return Validated
End Function
End Class
looks like you compare all user names and passwords to the strings "Username" and "Password" by calling:
Return UserDB.ValidateUser("Username", "Password")
in isValidUser.Probably you should better pass the actual username and the password which the user has typed instead?
There are a couple of problems in your code:
First I can't see anywhere the call to UserDB.GetUsers that should initialize the list of users from the file. But also assuming that you have made the call in some other place, there is another problem in that method.
This line inside the GetUsers method creates a new variable of type List(Of User) and name it with the same name of the Shared one effectively hiding the one declared at the global class level
Dim Users As New List(Of User)
Then your code continue and fills a variable named Users but this variable is not the shared one declared at the class global level. Of course, when you search your username and password in the shared variable you don't find anything.
Just remove that line and let the call To GetUsers fill the same variable used in the check
(Of course I also assume that when you call UserDB.ValidateUser you will pass an actual Username and a password and not the placeholders string that you are using in the code above)

Multiple Search Criteria (VB.NET)

So my problem is:
I have a List of a custom Type {Id as Integer, Tag() as String},
and i want to perform a multiple-criteria search on it; eg:
SearchTags={"Document","HelloWorld"}
Results of the Search will be placed a ListBox (ListBox1) in this format:
resultItem.id & " - " & resultItem.tags
I already tried everything i could find on forums, but it didn't work for me (It was for db's or for string datatypes)
Now, i really need your help. Thanks in advance.
For Each MEntry As EntryType In MainList
For Each Entry In MEntry.getTags
For Each item As String In Split(TextBox1.Text, " ")
If Entry.Contains(item) Then
If TestIfItemExistsInListBox2(item) = False Then
ListBox1.Items.Add(item & " - " & Entry.getId)
End If
End If
Next
Next
Next
Example Custom Array:
(24,{"snippet","vb"})
(32,{"console","cpp","helloworld"})
and so on...
I searched for ("Snippet vb test"):
snippet vb helloWorld - 2
snippet vb tcpchatEx - 16
cs something
test
So, i'll get everything that contains one of my search phrases.
I expected following:
snippet vb tcp test
snippet vb dll test
snippet vb test metroui
So, i want to get everything that contains all my search phrases.
My entire, code-likely class
Imports Newtonsoft.Json
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Dim MainList As New List(Of EntryType)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MainList.Clear()
Dim thr As New Threading.Thread(AddressOf thr1)
thr.SetApartmentState(Threading.ApartmentState.MTA)
thr.Start()
End Sub
Delegate Sub SetTextCallback([text] As String)
Private Sub SetTitle(ByVal [text] As String) ' source <> mine
If Me.TextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetTitle)
Me.Invoke(d, New Object() {[text]})
Else
Me.Text = [text]
End If
End Sub
Sub thr1()
Dim linez As Integer = 1
Dim linex As Integer = 1
For Each line As String In System.IO.File.ReadAllLines("index.db")
linez += 1
Next
For Each line As String In System.IO.File.ReadAllLines("index.db")
Try
Application.DoEvents()
Dim a As saLoginResponse = JsonConvert.DeserializeObject(Of saLoginResponse)(line) ' source <> mine
Application.DoEvents()
MainList.Add(New EntryType(a.id, Split(a.tags, " ")))
linex += 1
SetTitle("Search (loading, " & linex & " of " & linez & ")")
Catch ex As Exception
End Try
Next
SetTitle("Search")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim searchTags() As String = TextBox1.Text.Split(" ")
Dim query = MainList.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
ListBox1.Items.Add(et.Id)
Next
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) ' test
MsgBox(Mid(ListBox1.SelectedItem.ToString, 1, 6)) ' test
End Sub 'test, removeonrelease
End Class
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As String
Public Sub New(ByVal _id As Integer, ByVal _tags() As String)
Me.Id = Id
Me.Tags = Tags
End Sub
Public Function GetTags() As String
'to tell the Listbox what to display
Return Tags
End Function
Public Function GetId() As Integer
'to tell the Listbox what to display
Return Id
End Function
End Class
I also edited your EntryType class; I added a constructor, removed toString and added GetTags and GetID.
Example "DB" im working with ("db" as "index.db" in exec dir):
{"tags":"vb.net lol test qwikscopeZ","id":123456}
{"tags":"vb.net lol test","id":12345}
{"tags":"vb.net lol","id":1234}
{"tags":"vb.net","id":123}
{"tags":"cpp","id":1}
{"tags":"cpp graphical","id":2}
{"tags":"cpp graphical fractals","id":3}
{"tags":"cpp graphical fractals m4th","id":500123}
Error:
Debugger:Exception Intercepted: _Lambda$__1, Form2.vb line 44
An exception was intercepted and the call stack unwound to the point before the call from user code where the exception occurred. "Unwind the call stack on unhandled exceptions" is selected in the debugger options.
Time: 13.11.2014 03:46:10
Thread:<No Name>[5856]
Here is a Lambda query. The Where filters on a predicate, since Tags is an Array you can use the Any function to perform a search based on another Array-SearchTags. You can store each class object in the Listbox since it stores Objects, you just need to tell it what to display(see below).
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As As String
Public Overrides Function ToString() As String
'to tell the Listbox what to display
Return String.Format("{0} - {1}", Me.Id, String.Join(Me.Tags, " "))
End Function
End Class
Dim searchTags = textbox1.Text.Split(" "c)
Dim query = mainlist.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
Listbox1.Items.Add(et)
Next

how to pick value and name for item in listbox in vb.net

i want to pick payrollcode when listbox is selected though list should appear as payrollname.Once I have the paycode i can then use it in another query.I have a php background so this is alittle tricky for me.
Dim cmd As New SqlCommand("select tblPayrollCode.payrollcode_name ,tblPayrollCode.payrollcode_code from tblPayrollCode where tblPayrollCode.systemcode_id=0 and tblPayrollCode.deduction= 'false'", Getconnect)
Dim dr As SqlDataReader
Getconnect()
dr = cmd.ExecuteReader
While dr.Read
lsttrans.Items.Add(dr.Item("payrollcode_name"), payrollcode_code)
End While
dr.Close()
Create a class to create objects that keep each display item/data pair. The class needs to specify an overriden ToString method. This method overrides the ToString method of the base class (Object) to ensure that your display item and not the class name is displayed in the list box.
Public Class CListItem
Private m_sItemData As String
Private m_sItemDisplay As String
Public Sub New(ByVal sValue As String, ByVal sData As String)
m_sItemData = sData
m_sItemDisplay = sValue
End Sub
Public Overrides Function ToString() As String
Return m_sItemDisplay
End Function
Public Property ItemData() As String
Get
Return m_sItemData
End Get
Set(ByVal Value As String)
m_sItemData = Value
End Set
End Property
Public Property ItemDisplay() As String
Get
Return m_sItemDisplay
End Get
Set(ByVal Value As String)
m_sItemDisplay = Value
End Set
End Property
End Class
Execute the loop like this. This adds a CListItem object to the list box's items collection and displays the first parameter that is passed to the constructor.
While dr.Read
lsttrans.Items.Add(New CListItem(dr.Item("payrollcode_name").ToString, dr.Item("payrollcode_code").ToString))
End While
You can then retrieve the payrollcode_name and payrollcode_code by adding this code and double clicking on the list box:
Private Sub lsttrans_DoubleClick(sender As Object, e As EventArgs) Handles lsttrans.DoubleClick
Dim sSelectedDisplay As String = DirectCast(lsttrans.SelectedItem, CListItem).ItemDisplay
Dim sSelectedData As String = DirectCast(lsttrans.SelectedItem, CListItem).ItemData()
MessageBox.Show("The selected payrollcode_name is " & sSelectedDisplay & " and the selected payrollcode_code is " & sSelectedData)
End Sub
Adding onto #Guru Josh's answer
While dr.Read
lsttrans.Items.Add(New CListItem(dr.Item("payrollcode_name"), dr.Item("payrollcode_code")))
End While
I changed the last bit to the above works fine now.
string col1Value = dr["ColumnOneName"].ToString()