Is Databinding Textboxes in VB.net with a WHERE clause possible? - vb.net

Is there a way to add databindings including a WHERE clause to sort which rows in the table get bound to which text boxes?
Serialnametxtbx.DataBinding.Add(New System.Windows.Forms.Binding("Text", Me.CoatingKitsBindingSource, "Serial_Number", True, DataSourceUpdateMode.OnValidation, nullValue As Object, formatString As String)
I'm not sure what one should use in the nullValue As Object location and the formatString As String location?
In the below code I have added a WHERE statement as to what I would like to sort this by but I am not sure where to implement it.
Serialnametxtbx.DataBinding.Add(New System.Windows.Forms.Binding("Text", Me.CoatingKitsBindingSource, "Serial_Number WHERE [Description] LIKE '%Banana%'", True, DataSourceUpdateMode.OnValidation, nullValue As Object, formatString As String)
Any suggestions? :)
The scenario here is there are 7 items to which need to be assigned as a group to say Kit #1. Each of these Items have similarities, Description, Unit Number, Serial Number,Make,Model,Last Calibration, Next Calibration, Calibration Company, Status and Condition. For each of the 7 Items there is different information that the user has input into each of these ten text boxes when they have added the piece of equipment. So I need to bind the piece of equipment's information to individual groups of text boxes on a form for that kit number.
So there are 10 text boxes for each piece of equipment in a kit and there are 7 pieces of equipment in a kit meaning 70 text boxes to the form. In the table there are the 10 columns for each piece and I would like to bind them as they differentiate by their description.
To select the kit number the user would like to edit I used a binding source filter on a combobox:
Me.Coating_KitsTableAdapter.FillBy(MacroQualityDataSet.Coating_Kits)
Me.CoatingKitsBindingSource.Filter = ("Unit_Number LIKE '%" & selectcktxtbx.Text & "%'")
And populated the list items in it with a dataset which is created when the form loads:
Dim ds As New DataSet
Dim cs As String = My.Settings.MacroQualityConnectionString
Dim sql As String = "SELECT DISTINCT Coating_Kits.Unit_Number FROM Coating_Kits"
Dim connection As New SqlConnection(cs)
Dim da As New SqlDataAdapter(sql, connection)
connection.Open()
da.Fill(ds, "Coating_Kits")
connection.Close()
selectcktxtbx.DataSource = ds.Tables(0)
selectcktxtbx.DisplayMember = "Unit_Number"
Can I maybe do a databinding off this dataset? I'm totally lost as usual.. :(

Use the Filter property of the BindingSource; the two mystery parameters to the Binding constructor are irrelevant (they represent DBNull replacements and display formatting strings respectively). Untested:
CoatingKitsBindingSource.Filter = "[Description] LIKE '%Banana%'"
Note also that you'll need multiple binding sources if you need different filters, or one control filtered and one not.

Related

VB.NET Combo Box with multiple fields to select from

I'm porting an Access database I wrote over to VB.NET and while I've used Access for 25 years, I've used VB.NET for 2 days so I'm unclear what the capabilities are.
In my Access form, I have a Combo Box which allows the user to select a part record from a table. Using Access I can show multiple columns to the user making a selection - PartID, Description, notes, whatever. However once the part is selected and the combo box is closed, I show only the unique part ID. The other columns help the user choose but make the form look really cluttered.
In my VB.NET form, I set the ValueMember to the PartID. But I only know how to set the DisplayMember to a single field. I created a composite field "PartID | Description | Notes" but then that's what appears even after the selection is made.
Is it possible in VB.NET to show one thing when the box is open and another thing once the selection has been made?
qry = "SELECT PartID, cast(PartID as string) & " | " & [partName] AS PartString
FROM [Part_List]
GROUP BY PartID, cast(PartID as string) & " | " & [partName]
ORDER BY PartID;"
cmd = New SqlCommand(qry, conn)
adapter = New SqlDataAdapter(cmd)
Dim tblPN As New DataTable()
adapter.Fill(tblPN)
ChoosePartNum.DataSource = tblPN
ChoosePartNum.DisplayMember = "PartString"
ChoosePartNum.ValueMember = "PartID"
ChoosePartNum.SelectedIndex = -1
I see what you are trying to do. I was doing that in MS Access too but it was more than 20 years ago.
I agree with Jimi. From a design point of view, trying to reproduce Access-like features in a new environment is not a great idea.
Users are familiar with Winforms controls and have certain expectations in term of UI layout and consistency. If you are building a new UI from scratch you should take the opportunity to redesign it and modernize it. Don't just carry 25-year old habits over. Especially if you are not the only user of that application, because you don't want people to think that your coding methods are stuck in the 20th century...
Is it possible in VB.NET to show one thing when the box is open and
another thing once the selection has been made?
If you really want to achieve this behavior you need to use combo box events. The two events you need would be DropDownClosed and DropDown.
Here is how it can be done:
Private Sub ComboBox1_DropDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.DropDown
With Me.ChoosePartNum
.DisplayMember = "composite field"
End With
End Sub
Private Sub ComboBox1_DropDownClosed(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.DropDownClosed
With Me.ChoosePartNum
.DisplayMember = "PartID"
End With
End Sub
The trick is to change the DisplayMember property whenever the combo box is folded/unfolded by the user. The underlying value remains the same.
I don't know if you require autocomplete from keyboard or have other needs. A treeview or listview sound like obvious alternatives. But you said you want a 'compact' control. Here you go.

VB.Net Dynamically Referencing a Variable or Control

It would take too long to try an explain the actual application I am building.
Lets just say, I have 3 textboxes on my form. I want to set each one of them to a value of the numerical index. This is how I would normally do it.
txt1.Text = "1"
txt2.Text = "2"
txt3.Text = "3"
Now, if I had 100 of these textboxes, I would want to do something more like this.
For i as Integer = 1 to 3
txt[i].Text = i
Next
Is this possible?
This is how I would do it: first, create a list or an array (depending on whether the number of textboxes is fixed or not) and add you textboxes to it:
Dim txtList as new list(of textbox)
txtList.items.add(txtBox1...
This can be done automatically using jmcilhinney's method (with the same caveats):
Dim txtList = New List(Of TextBox)(Me.Controls.OfType(Of TextBox)().ToArray())
Then you can reference it as such:
txtList(i).text
I hope that's what you were asking and that it helps :)

Display members and Value members

Hi I am new to VB platform, Can any one help me to understand the last few lines of code, here I highlight with bold at last, which is not understand or confusing to me. What does that Display member and value number do?
.. cmbcust is the combobox...
Where customer table are having following field.
**Customer_sname** **Customer_code** **Customer_fname**
nokia 1 nokia corp.
samsung 2 samsung corp.
sony 3 sony corp.
Micromax 4 Micromax India corp.
passing custval is nokia, samsung, sony
Public Function customfunc(ByVal custval As String) As DataSet
Try
Dim strSQL As String = "select * from customer where cust_sname in (" & custval & ")"
If Conn.State = ConnectionState.Open Then Conn.Close()
Conn.Open()
Dim Adap As New SqlDataAdapter(strSQL, Conn)
Dim Ds As New DataSet
Adap.Fill(Ds, "customer")
ReadINICustomers = Ds
Catch EXP As Exception
MsgBox("Error Connecting to Server :" & EXP.Message, MsgBoxStyle.Critical)
End Try
End Function
Public Sub Fillcustomer()
Dim Lstcust() As String
Dim Lstcust1 As String
Lstcust1 = ""
Lstcust1 = custINIval
Dim Ds As New DataSet
Ds = objData.ReadINICustomers(Lstcust1)
cmbcust.DataSource = Ds.Tables("customer")
cmbcust.DisplayMember = Ds.Tables("customer").Columns.Item("cust_sname").ToString().Trim()
cmbcust.ValueMember = Ds.Tables("customer").Columns.Item("cust_code").ToString().Trim()
End Sub
cmbcust.DisplayMember =
Ds.Tables("customer").Columns.Item("cust_sname").ToString().Trim()
cmbcust.ValueMember = Ds.Tables("customer").Columns.Item("cust_code").ToString().Trim()
When working in any of the .NET languages, such as VB.NET, the MSDN is your friend. It is the official resource for documentation regarding the languages and all of the types in the .NET Framework. In this case, you are asking about a couple of properties on the ComboBox control. The first thing you should do, then, is to search the MSDN for the ComboBox class. If you do so, you will find this article. It lists all of the members of the class and has a separate article explaining each one. If you scroll down through the list of properties, you will find links to articles for the DisplayMember property and the ValueMember property.
As those articles describe, the ComboBox control can contain any type of objects in its list of items. If you put something simple like a list of strings into the ComboBox, then its obviously easy for it to determine what to display in the list and what to return for its current value. However, when you place complex custom objects in the ComboBox, it's a more difficult proposition.
By default, it will display whatever the ToString method returns for each of the objects in its list. However, by setting the DisplayMember property, you can instruct it to use a particular member (such as a Property or Function) of the objects in the list instead of the ToString method. You do so by setting the DisplayMember property to the string name of the objects' member. It then uses reflection to find the member by that name in each of the objects and retrieve its value.
The ValueMember is very similar, but rather than controlling what gets displayed, it controls what gets returned by the SelectedValue property. By default, the SelectedValue property simply returns the entire object that was selected in the list. However, by setting the ValueMember, you can instruct it to just return the value of one particular member from the object rather than the whole thing.

How should I handle filling multiple textboxes when I don't know how many of them will have data?

I'm writing an application in VB in which I need to show the user some information which will be copy and pasted into another application however limitations of the other application mean that the string needs to be split into chunks no larger than 55 characters (it's just written notes). I thought the neatest way to do this was to have several textboxes each with a 'copy to clipboard' button to make it convenient for the user.
The code I have is:
Dim invdesc As List(Of String) = Split(splitstring, 55)
txtinvDesc1.Text = invdesc(0)
txtinvDesc2.Text = invdesc(1)
txtinvDesc3.Text = invdesc(2)
...
Split uses a regular expression to return a list of several lines without breaking up words and most of the time this will return a maximum of seven results but occasionally six (my original string max length is 330) and often fewer so my original idea to fill out any strings shorter than 330 with trailing spaces won't work as it's still possible I will either miss text or call a result that isn't there.
Ideally I would just do some kind of loop that only inputs to txtinvDesc(x) while there is data available and ignores the rest (or hides them) but I don't know any way to refer to a textbox other than explicitly or how to put them in any kind of list/array.
So it's a bit of an open question in "how best can I handle this requirement?"
You can create a collection (e.g., Array or List) of TextBox like with any other type/class (as you are doing with String in your code). Sample:
Dim allTextBoxes As New List(Of TextBox)
allTextBoxes.Add(txtinvDesc1)
allTextBoxes.Add(txtinvDesc2)
allTextBoxes.Add(txtinvDesc3)
Alternatively, you might iterate through all the controls in the main form by checking its type (a textbox or not). In that case you would have to set a relationship between the given name of the textbox and the data list index, via other collection for example:
Dim mappingList As New List(Of String)
mappingList.Add("txtinvDesc1")
mappingList.Add("txtinvDesc2")
mappingList.Add("txtinvDesc3")
For Each ctr As Control In Me.Controls
If (TypeOf ctr Is TextBox AndAlso mappingList.Contains(ctr.Name)) Then
ctr.Text = invdesc(mappingList.IndexOf(ctr.Name))
End If
Next
--- CLARIFICATION (not as evident as I thought)
The proposed for each loop relies on a mapping approach, that is, it relates each element in invdesc with the corresponding TextBox name. By definition, both arrays HAVE TO have the same number of elements (otherwise the mapping system wouldn't have made any sense). This is the most efficient and overall-applicable alternative; if the names of the textboxes and invdesc have elements in common (e.g., the numbers), you might just compare the names. BUT WHEN MAPPING YOU HAVE TO ACCOUNT FOR ALL THE ELEMENTS (if there is no associated TextBox to a given item, let the value blank; but all the items have to be accounted).
If you want to index the tbs:
Private TBs as New List (of TextBox)
Early on (after FormLoad) maybe in a FormSetup:
TBs.Add(txtinvDesc1)
TBs.Add(txtinvDesc2)
TBs.Add(txtinvDesc3)
...
Then:
Dim invdesc As List(Of String) = Split(splitstring, 55)
For n As Integer = 0 To invdesc.Count-1
TBs(n).Text = invdesc(n)
Next
' handle the varying 7th TB:
For n As Integer = invdesc.Count-1 To TBs.Count - 1
TBs(n).Enabled = False
TBs(n).Text =""
Next
Or a For/Each:
Dim ndx As Integer = 0
For Each tb As TextBox In TBs
tb.Text = invdesc(ndx)
ndx += 1 ' thanks varo!
Next
Then hide/disable or at least clear the text from any empty ones.
If it turns out there are always 6 you really only need an if statement:
txtinvDesc1.Text = invdesc(0)
txtinvDesc2.Text = invdesc(1)
txtinvDesc3.Text = invdesc(2)
...
If incDesc.Count-1 = 6 Then
txtinvDesc7.Text = invdesc(6)
Else
txtinvDesc7.Enabled= False
txtinvDesc7.Text = ""
End If
I would change the TB names to start at txtinvDesc0.Text to avoid getting confused (as I may have)
Use multiline textbox and in OnKeyPress event force 55 chars per line. You can find subclassed TextBox with that feature in this SO answer :
https://stackoverflow.com/a/17082189/351383

Need Suggestions For AutoSuggest For VB.NET ComboBox

To provide some context, I have a combobox that the user interacts with to select an insurance company. Unfortunately they don't require just the name; sometimes insurance companies have the same name, and the only way to distinguish between them is to use their address (eg a Medicare office in North Carolina vs. a Medicare office in South Carolina). What I've currently done is use the combobox's DrawItem event to draw a tooltip next to the ComboBox when the dropdown list is displayed. The list itself displays the insurance company names, but the tooltip will display the address of the currently selected company. The combobox is set to DropDownList, so it's impossible for them to pick anything but what's in the list.
Well, now I'm being told to change this. The users are no longer content to have to click the combobox or hit the arrow keys. They want comboboxes that they can type in and have an autosuggest list appear as they type. That's all well and good but this is where I'm running into a wall. My cute little scheme of using a tooltip can't work in that situation because the autosuggest list is a completely separate control. DrawItem doesn't touch it, and I can't find a way to custom draw the autosuggest list. The other problem is that autosuggest doesn't do duplicate entries, so even though I have two different insurance companies only one will appear in the list simply because they share the same name.
The only other idea I've had so far is to somehow scroll the dropdown list to the appropriate item upon the user pressing a key. But I can't figure out how to set the highlighted item in the dropdown list without setting selectedindex. If I use selectedindex, it goes ahead and replaces the text.
Does anyone have any suggestions for how to proceed? Am I on the right track, or do am I trying too hard and need to do something else entirely?
You could use a text field where the user types in their text, and narrow the selection in the dropbox down based on that. To get around the same-name-but-different-company problem, you could list the address of the company after the name in a parenthesis. If the user types in a name that is invalid, put up an error/warning icon next to the text field.
To update the selection at runtime, you can add an event listener to the text field and query the current text to decide whether it is a valid prefix, or not.
We do something similar at the company I'm at. To accomplish it, we utilize a web service through AJAX.
Essentially, you modify a standard textbox with an AJAX AutoCompleteExtender (ACE). This ace references a webservice (which I'll illustrate) that goes and gets the info the customer types in on the fly. It's pretty cool once it's up and running.
Here's an example:
.ascx
<asp:TextBox ID="txtInsuranceCompany" runat="server" TabIndex="520"
AutoComplete="Off"AutoCompleteType="Disabled" CssClass="asbSearch" Width="350px"></asp:TextBox>
<ajax:AutoCompleteExtender ID="aceInsuranceCompany" runat="server" CompletionSetCount="20"
MinimumPrefixLength="0" OnClientShown="resetPosition" ServiceMethod="LookupData"
ServicePath="~/WebLookUpService.asmx" TargetControlID="txtInsuranceCompany" UseContextKey="true">
</ajax:AutoCompleteExtender>
Something subtle is that you have to be sure you set the context key for your autocomplete extender, as well as create some functionality within your webservice to load your values (again, I'll illustrate).
.vb code-behind
Dim yourhardcodedlist As New List(Of String)
yourhardcodedlist.Add("Progressive")
yourhardcodedlist.Add("State Farm")
yourhardcodedlist.Add("USAA")
WebLookUpService.AddLookupValues(txtInsuranceCompany.ID, yourhardcodedlist.ToArray)
aceInsuranceCompany.ContextKey = public_var0 & ":" & public_var1 & ":" & txtInsuranceCompany.ID
Note that the "public_var0" "and public_var1" aren't mandatory. This is just illustrating how you could pass more information to your web service without actually passing it as a parameter (i.e. a colon-delimitted list, that you're web service function can parse out for use in a SQL statement or something).
Now for the webservice...(.asmx)
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<System.Web.Script.Services.ScriptService()> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class WebLookUpService
Inherits System.Web.Services.WebService
<System.Web.Services.WebMethod(), System.Web.Script.Services.ScriptMethod()> _
Public Function LookupData(ByVal prefixText As String, ByVal count As Integer, ByVal contextKey As String) As String()
'Construct SQL statement to pull from database
'parsing the context key as necessary to construct your SQL statement (if necessary)
'Dim somethingForSql As String = contextKey.Split(":")
Dim suggestions As List(Of String) = New List(Of String)
Try
Using cnADO As SqlConnection = New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("PublicSafetyServer").ToString)
cnADO.Open()
Dim dt As DataTable = New DataTable
Dim da As New SqlDataAdapter
da.SelectCommand = New SqlCommand("<YourSQLStatement>")
da.Fill(dt)
Dim endRow As Integer = dt.Rows.Count
If endRow > count Then
endRow = count
End If
For i As Integer = 0 To endRow - 1
Dim des As String = dt.Rows(i).Item(field)
Dim val As String = dt.Rows(i).Item(field)
suggestions.Add(AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(des, val))
Next
End Using
Catch ex As Exception
'Throw Error
End Try
suggestions.Sort()
If suggestions.Count = 0 Then
suggestions.Add(AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(noneFound, ""))
End If
Return suggestions.ToArray()
End Function
What's cool is that you can add values deliberately through 'yourhardcodedlist' that will combine with any values you pull via the web-service. This way, you can add values directly if you can't add values to the database.