user assigning non-repeating values in a numerical list - sql

I'm creating an output ordering function. The user needs the ability to change the order frequently on the fly (it's used to order pick lists for our order pickers). I have created a Windows Form, but i need to do some validation on it. The validation itself is simple... the numbers have to be in order and can't repeat. If they repeat, the SQL report bombs out... I'd also like to validate not skipping any values, but that's not really necessary.
is there a better way than:
if NumericUpDown1.value = NumericUpDown2.value then
error goes here
end if
if NumericUpDown1.value = NumericUpDown3.value then
error goes here
end if
if NumericUpDown1.value = NumericUpDown4.value then
error goes here
end if ...
there is a large list, and this would be thousands of lines of code. I know there has got to be a simple solution. It's not coming to me, and i've been stuck on it for a couple of days. (yea I know i probably could have just done it already)

Just like Serg said, put the values into an array and use Linq to group by the values. Then find any duplicates.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim numericList = New Decimal() {
NumericUpDown1.Value,
NumericUpDown2.Value,
NumericUpDown3.Value,
NumericUpDown4.Value,
NumericUpDown5.Value
}
Dim duplicatesExist = numericList _
.GroupBy(Function(n) n) _
.Any(Function(g) g.Count() > 1)
If duplicatesExist Then
MessageBox.Show("Duplicates exist")
Else
MessageBox.Show("No Duplicates")
End If
End Sub

Related

Filtering binding source

This should be easy but I am having a headbanging of a time trying to get this to work! I have done a search and tried all most EVERY SINGLE ONE. Nothing works. I have a datagrid with a binding source. A user will type text into a textbox and the grid is SUPPOSED to change to only show records that contain what user typed in the name. Simple right? NOPE! Not for me! What am I doing wrong? Code below.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) Handles SearchButton.Click
Dim Found As Boolean = False
Dim StringToSearch As String = ""
Dim ValueToSearchFor As String = "%" & SearchTextBox.Text.Trim.ToLower & "%"
Dim CurrentRowIndex As Integer = 0
Try
If ReferencesGrid.Rows.Count = 0 Then
CurrentRowIndex = 0
Else
CurrentRowIndex = ReferencesGrid.CurrentRow.Index + 1
End If
If CurrentRowIndex > ReferencesGrid.Rows.Count Then
CurrentRowIndex = ReferencesGrid.Rows.Count - 1
End If
If ReferencesGrid.Rows.Count > 0 Then
For Each gRow As DataGridViewRow In ReferencesGrid.Rows
StringToSearch = gRow.Cells(1).Value.ToString.Trim.ToLower
If InStr(1, StringToSearch, LCase(Trim(SearchTextBox.Text)), vbTextCompare) Then
TrainingItemBindingSource.Filter = String.Format("Name LIKE '{0}'", ValueToSearchFor)
Exit For
End If
Next
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
You should get rid of pretty much all that code. If you want to filter the data then just filter the data. There's no conditional statements required and loops required. Just set the Filter property and any records that don't match the filter will be hidden:
Private Sub SearchButton_Click(sender As Object, e As EventArgs) Handles SearchButton.Click
TrainingItemBindingSource.Filter = $"Name LIKE '%{SearchTextBox.Text.Trim()}%'"
End Sub
As you can see, it is simple. I've no real idea what you were actually trying to achieve with the rest of that code. That will exclude any records where the Name column does not contain the search text.
Note that there is no need to try to force case-insensitivity by using ToLower or the like. Just like in real SQL, comparisons done this way in a DataTable are case-insensitive by default. You have to explicitly set the CaseSensitive property of the DataTable or its parent DataSet to True to make such comparisons case-sensitive.
I should also point out that the ability to filter is predicated on the data source implementing certain interfaces. If the data source is a DataTable then you have those interfaces for free. If you have actually bound to something else, e.g. a List(Of T), then you won't be able to filter this way because the required members do not exist.

LINQ Query in VB.net comparing integers

I am trying to write a LINQ query that compares an integer value in a database to an integer variable. This is not working. I can compare text values but comparing integers returns a null.
Private Sub txtRoomNum_TextChanged(sender As Object, e As EventArgs) Handles txtRoomNum.TextChanged
If Val(txtRoomNum.Text) > 99 Then
Dim intRoomNum As Integer
intRoomNum = Val(txtRoomNum.Text)
Dim RoomData = (From Rooms In BadermanIslandDataSet.Rooms
Where Rooms.HotelID = intHotelID).SingleOrDefault
''Where Rooms.HotelID = intHotelID And Rooms.RoomNumber = intRoomNum
Try
txtTest.Text = RoomData.RoomID
Catch ex As Exception
txtTest.Text = "null"
End Try
End If
End Sub
Change txtTest.Text = RoomData.RoomID
to Convert.ToInt32(txtTest.Text) = RoomData.RoomID)
You were comparing string and integer before
Since it's user input I would try using Integer.TryParse when getting the value from the text field. This will prevent an exception from being raised, and in the case the parse fails you can ask your user to only use a number in that field.
If Integer.TryParse(txtRoomNum.Text, intRoomNum) Then
...your logic
Else
...something to let them know to only put a number in txtRoomNum.Text
End If
Ok, I found the issue. I needed a RoomsBindingSource on the form. Once that was added it worked like a champ.

How do I read data in drop down?

I can view the data in textbox but the problem is, if I change it to drop down to show multiple data, it will give an empty data ..
Private Sub textbox2_SelectionChangeCommitted(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.KeyPress
Try
cmd = New Odbc.OdbcCommand("SELECT maker FROM pcba_info.tblvendorpartnumber WHERE partnumber ='" & Trim(TextBox2.Text.TrimEnd()) & "'", con)
dr = cmd.ExecuteReader
If dr.Read Then
TextBox55.Text = dr("maker").ToString ----------> return single data
TextBox12.SelectedIndex = dr("maker").ToString -----------> no data
dgvcertifiedoperator.DataSource = dt
dgvcertifiedoperator.Update()
dgvcertifiedoperator.Refresh()
End If
Catch ex As Exception
Debug.WriteLine("Plz check the parts" & ex.Message)
End Try
End Sub
I am assuming that your TextBox12 represents a dropdown. In this case assigning SelectedIndex to a string is incorrect (just think about it for a second - an index cannot be a string, i.e. AAA is not an index). Use Option Strict On to prevent such errors.
See, by default, VB.NET does not prevent you from doing it, because theoretically a string can be an integer, so this statement can work. But it does not mean it will work 100% of the time. Option Strict validates type conversion to ensure it always works, or your code does not compile.
Back to your question, one way to do it is to accumulate values in a list, then make that list a data source for your dropdown, like this:
Dim lst As New List(Of String)
While dr.Read Then
lst.Add(dr("maker").ToString)
End While
TextBox12.DataSource = lst
You can then retrieve current value by using TextBox12.SelectedItem, cast to string:
DirectCast(TextBox12.SelectedItem, String)
A side note - make sure your controls are named accordingly. TextBox is usually reserved for, well, text boxes. Dropdowns are usually MakerComboBox, MakerDropDown etc. Avoid naming your controls like TextBox56 and ComboBox188, because those numbers are meaningless for another developer. Even if you are the only one on the project, consider us helping you with it.

VB.NET Combobox - Auto-complete behaviour for numeric values

I have a problem with the auto-complete behaviour of comboboxes in VB.NET (with the .NET framework 2.0).
I am using a combobox to type in numeric values, and its DropDown list to suggest possible numeric values. This list is sorted in ascending order, for example {"10","92", "9000", "9001"}.
The combobox properties are set as follow:
AutoCompleteMode: SuggestAppend
AutoCompleteSource: ListItems
DropDownStyle: DropDown
Sorted: False
The DropDown list is simply filled like this:
myCombobox.Items.Add("10")
myCombobox.Items.Add("92")
myCombobox.Items.Add("9000")
myCombobox.Items.Add("9001")
When I don't type anything, the order of values of the DropDown list is correct, in original/ascending order. However, when I start typing something, the suggested values in the DropDown list get sorted (alphanumerically): if I type "9", the list of suggestions becomes {"9000", "9001", "92"}.
I would like to prevent this behaviour to get the values of the list in the original/ascending order. I can't figure out how...
A possible work-around would be to pad with zeroes the values in the list, e.g. {"0010", "0092", "9000", "9001"} but I would like to avoid this.
Edit:
As suggested by bendataclear, one can use a list box to display the suggestions.
This will work for small lists but doesn't scale well to large lists. It may be useful for some applications. Based on the code given by bendataclear, I made it work this way:
Private Sub ComboBox1_KeyUp(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyUp
Dim cursorPos As Integer = ComboBox1.SelectionStart
ListBox1.Items.Clear()
For Each s In ComboBox1.Items
If s.StartsWith(ComboBox1.Text) Then
ListBox1.Items.Add(s)
End If
Next
If ListBox1.Items.Count > 0 And ComboBox1.Text.Length > 0 Then
ComboBox1.Text = ListBox1.Items(0)
ComboBox1.SelectionStart = cursorPos
ComboBox1.SelectionLength = 0
End If
End Sub
The code has not been thoroughly tested and can be improved, but the main idea is there.
Edit 2:
Using DataGridView leads to better performance; it was sufficient for me. Thanks bendataclear.
Just out of curiosity, any other answer is welcomed :)
Seems to be an issue when the combo box displays the data, as even if you set a custom source it re-orders alphabetically:
ComboBox1.Items.Add("10")
ComboBox1.Items.Add("92")
ComboBox1.Items.Add("9000")
ComboBox1.Items.Add("9001")
ComboBox1.AutoCompleteCustomSource.Add("10")
ComboBox1.AutoCompleteCustomSource.Add("92")
ComboBox1.AutoCompleteCustomSource.Add("9000")
ComboBox1.AutoCompleteCustomSource.Add("9001")
ComboBox1.AutoCompleteSource = AutoCompleteSource.CustomSource
I think the only way I can think of is to create your own autocomplete something like (untested):
Dim cbotxt As String = ComboBox1.Text
Dim key As String
key = ChrW(e.KeyCode)
ListBox1.Items.Clear()
For Each i In ComboBox1.Items
Dim s As String = i.ToString()
If s.StartsWith(ComboBox1.Text & key) Then
ListBox1.Items.Add(s)
End If
Next
If ListBox1.Items.Count > 0 Then
ListBox1.Visible = True
ComboBox1.Text = ListBox1.Items(0)
End If
Edit:
A good approach for many items (I'm using for 10000+ in an application):
First change from a list box to a datagridview.
Then declare a list of strings and fill with values you want to autocomplete
Dim Numberlist as List<Of String>
' Fill List using Numberlist.Add("String")
Then in the text change property:
Filter = NumberList.FindAll(AddressOf checkNum)
DataGridView1.DataSource = Filter
And add the function to check the strings.
Function checkNum(ByVal b As String) As Boolean
If b.StartsWith(ComboBox1.Text) Then
Return True
Else
Return False
End If
End Function
This method runs on my machine with 10k items faster than I can type.

How To Read From Text File & Store Data So To Modify At A Later Time

What I am trying to do may be better for use with SQL Server but I have seen many applications in the past that simply work on text files and I am wanting to try to imitate the same behaviour that those applications follow.
I have a list of URL's in a text file. This is simple enough to open and read line by line, but how can I store additional data from the file and query the data?
E.g.
Text File:
http://link1.com/ - 0
http://link2.com/ - 0
http://link3.com/ - 1
http://link4.com/ - 0
http://link5.com/ - 1
Then I will read the data with:
Private Sub ButtonX2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonX2.Click
OpenFileDialog1.Filter = "*txt Text Files|*.txt"
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
Dim AllText As String = My.Computer.FileSystem.ReadAllText(OpenFileDialog1.FileName)
Dim Lines() = Split(AllText, vbCrLf)
Dim list = New List(Of Test)
Dim URLsLoaded As Integer = 0
For i = 0 To UBound(Lines)
If Lines(i) = "" Then Continue For
Dim URLInfo As String() = Split(Lines(i), " - ")
If URLInfo.Count < 6 Then Continue For
list.Add(New Test(URLInfo(0), URLInfo(1)))
URLsLoaded += 1
Next
DataGridViewX1.DataSource = list
LabelX5.Text = URLsLoaded.ToString()
End If
End Sub
So as you can see, above I am prompting the user to open a text file, afterwards it is displayed back to the user in a datagridview.
Now here is my issue, I want to be able to query the data, E.g. Select * From URLs WHERE active='1' (Too used to PHP + MySQL!)
Where the 1 is the corresponding 1 or 0 after the URL in the text file.
In the above example the data is being stored in a simple class as per below:
Public Class Test
Public Sub New(ByVal URL As String, ByVal Active As Integer)
_URL = URL
_Active = Active
End Sub
Private _URL As String
Public Property URL() As String
Get
Return _URL
End Get
Set(ByVal value As String)
_URL = value
End Set
End Property
Private _Active As String
Public Property Active As String
Get
Return _Active
End Get
Set(ByVal value As String)
_Active = value
End Set
End Property
End Class
Am I going completely the wrong way about storing the data after importing from a text file?
I am new to VB.NET and still learning the basics but I find it much easier to learn by playing around before hitting the massive books!
Working example:
Dim myurls As New List(Of Test)
myurls.Add(New Test("http://link1.com/", 1))
myurls.Add(New Test("http://link2.com/", 0))
myurls.Add(New Test("http://link3.com/", 0))
Dim result = From t In myurls Where t.Active = 1
For Each testitem As Test In result
MsgBox(testitem.URL)
Next
By the way, LINQ is magic. You can shorten your loading/parse code to 3 rows of code:
Dim Lines() = IO.File.ReadAllLines("myfile.txt")
Dim myurls As List(Of Test) = (From t In lines Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
DataGridViewX1.DataSource = myurls
The first line reads all lines in the file to an array of strings.
The second line splits each line in the array, and creates a test-item and then converts all those result items to an list ( of Test).
Of course this could be misused to sillyness by making it to a one-row:er:
DataGridViewX1.DataSource = (From t In IO.File.ReadAllLines("myfile.txt") Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
Wich would render your load function to contain only following 4 rows:
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
DataGridViewX1.DataSource = (From t In IO.File.ReadAllLines("myfile.txt") Select New Test(Split(t, " - ")(0), Split(t, " - ")(1))).ToList
LabelX5.Text = ctype(datagridviewx1.datasource,List(Of Test)).Count
End If
You can query your class using LINQ, as long as it is in an appropriate collection type, like List(of Test) . I am not familiar completely with the VB syntax for LINQ but it would be something like below.
list.Where(Function(x) x.Active == "1").Select(Function(x) x.Url)
However, this isnt actually storing anything into a database, which i think your question might be asking?
I think you are reinventing the wheel, which is not generally a good thing. If you want SQL like functionality just store the data in a SQL DB and query it.
There are a lot of reasons you should just use an existing DB:
Your code will be less tested and thus more likely to have bugs.
Your code will be less optimized and probably perform worse. (You were planning on implementing a query optimizer and indexing engine for performance, right?)
Your code won't have as many features (locking, constraints, triggers, backup/recovery, a query language, etc.)
There are lots of free RDBMS options out there so it might even be cheaper to use an existing system than spending your time writing an inferior one.
That said, if this is just an academic exercise, go for it. However, I wouldn't do this for a real-world system.