Can you help me with my problem in navigating BindingSource.
I want to convert this vb6 code in vb.net using BindingSource
Do Until recordSet.EOF
if isnull(resordSet!FieldName)=true then
recordSet.delete
end if
recordset.movenext
loop
You can replace the entire loop with BindingSource.Clear:
The Clear method removes all elements from the underlying list
represented by the List property and sets the Count property to zero.
This method raises the ListChanged event.
Related
I would like to know please if there is any proper way to validate empty fields inside a DataGridView. I mean, that there are no empty rows inside the grid. (not just fields, the entire row).
Please if anyone has any idea of the event I should use or the code it would be very helpful. Thank you in advance.
This is what I would do:
Use the cast method (documentation) on the Rows collection to an IEnumerable(Of DataGridViewRow)
Use the where method (documentation) to iterate over the collection
Use the cast method on the Cells collection of the currently iterated row to an IEnumerable(Of DataGridViewCell)
Use the all method (documentation) to iterate over the collection
Use a conditional statement to check where the cell's value is nothing
Example:
Dim emptyRows = DataGridView1.Rows.Cast(Of DataGridViewRow).Where(Function(row) row.Cells.Cast(Of DataGridViewCell).All(Function(cell) cell.Value Is Nothing))
If (emptyRows.Any()) Then
' do something with the empty rows
End If
I have a code that deletes the textbox and datetimepicker i create in a panel... delete code is working for all the TEXTBOX but when its time to delete the datetimepickers it does not delete all the datetimepicker.
Example: there are 4 textbox and 4 datetimepickers when it runs the code the panel will delete all 4 textbox but deletes 2 datetiepickes only. I really cant find out what is wrong. Please help me... Thanks!
code is here:
For Each ctrlTxt As TextBox In panelGroupDependent.Controls.OfType(Of TextBox)()
ctrlTxt.Dispose()
Next
For Each ctrlDtp As DateTimePicker In panelGroupDependent.Controls.OfType(Of DateTimePicker)()
ctrlDtp.Dispose()
Next
As it stands, you are modifying a collection as you are enumerating it, which is not allowed. A For Each loop enumerates a collection so you are not allowed to add or remove items within the loop. When you dispose a control, it is removed from its parent container and thus you are modifying the Controls collection of that parent.
The OfType method doesn't actually generate a new collection of items but rather enumerates the collection it's called on and yields the items of the specified type one by one. As such, enumerating the result of OfType means enumerating the source collection at the same time.
By calling ToArray, you complete the enumeration of the source collection first and populate an array with the items of the specified type, then enumerate that array using the For Each loop. Disposing the controls has no effect on the array so there's no issue.
For Each ctrlTxt In panelGroupDependent.Controls.
OfType(Of TextBox)().
ToArray()
ctrlTxt.Dispose()
Next
For Each ctrlDtp In panelGroupDependent.Controls.
OfType(Of DateTimePicker)().
ToArray()
ctrlDtp.Dispose()
Next
Note that there is also no need to declare the type of the loop control variables as it can be inferred.
Into a VB.NET project I have some controls with multiple tags, separated by commas. Into a For Each loop I am trying to check if those controls contain some of those tags and then do stuff. Sometimes it works, sometimes not, and I get an error message!!! Here is an example of my code..
This public sub placed into a module:
Public Sub AllForms_BottomButtons_Appearence()
For Each OpenForms As Form In My.Application.OpenForms
For Each FlowLayoutPanel As Control In OpenForms.Controls
If FlowLayoutPanel.Tag.ToString.Contains("Something") Then
For Each Label As Label In FlowLayoutPanel.Controls
If Label.Tag.ToString.Contains("Something") Then
'Some Code Here...
End If
Next
End If
Next
Next
End Sub
At second IF where I am trying to check if a Label's tag contains something, I have no problem. But at first IF where I am trying to check if a FlowLayoutPanel's tag contains something, I get this exception message Object variable or With block variable not set.
If I change my first IF to something else but tag, for example If FlowLayoutPanel.Name.ToString.Contains("Something") Then, I get no exception message and my application works fine without stop at my second IF.
Do you see something I can't see?
The error occurs because one (or more) of the controls you are iterating have no tag, i.e. it's null. You need to add null-checking to both of your If-statements to ensure that no such errors occur.
If FlowLayoutPanel.Tag IsNot Nothing AndAlso FlowLayoutPanel.Tag.ToString().Contains("Something") Then
For Each Label As Label In FlowLayoutPanel.Controls.OfType(Of Label)()
If Label.Tag IsNot Nothing AndAlso Label.Tag.ToString().Contains("Something") Then
'Some Code Here...
End If
Next
End If
Error reference: Object variable or With block variable not set - Microsoft Docs
As you may have noticed changed your second loop to:
For Each Label As Label In FlowLayoutPanel.Controls.OfType(Of Label)()
This is because you shouldn't assume that every matching control (the FlowLayoutPanel variable) contains only labels. If you suddenly would've added another type of control to one of your FlowLayoutPanels then your initial loop would've thrown an exception because it cannot cast that control to a Label.
The OfType(Of TResult) extension ensures that you only iterate objects of the specified type, in this case Labels.
Finally, you should avoid using Application.OpenForms, it's buggy: https://stackoverflow.com/a/3751748
I just started rewriting an application from vba (Access) to vb.net + SQLServer so not very experienced in .net.
I am creating custom controls (Form + form controls) with a number of extra properties PrevValue, Modified (similar then the one of Textbox), Dirty, DirtyEnabled, SQLColumnName, SQLTableName to enable AutoUpdating and undoing in my forms the form exposes IsDirty, Initialising and Isready properties and an undo method.
Doing so it occurs that I have to write 3 times the same iteration code in different places:
For each Ctrl as Control in frm.Controls ' frm being a reference to the form
if typeOf Ctrl is MyTextBox
with DirectCast(Ctrl, MyTextBox)
' here comes the variable code depending what needs to be done
end with
elseif TypeOf Ctrl is MyComboBox
' etc.... for MyListBox, MyCheckBox etc....
I also have a number of custom controls MyNumBox and MyDateBox that inherit from MyTextBox but with some modified behavior (Formula evaluation, date manipulation, calendar...) how do I avoid doing an extra test on them.
One version of this Iteration is in the SQLProcessClass where the modified controls are added as SQLParameter and after iteration calling the SQLProcessClass Update or Insert, but ... after successful SQL activity I need to iterate through the controles again to reset the modified flag for each control. Elsewhere I need it to implement a form undo to reset all the controls to their previous values.
It seems to me I have two options
1. repeating that iteration code everywhere I need to iterate through the forms controls. I don't like it as every time I would need to create a new custom control I have to add some lines X times in different modules/classes ... very bad programming
2. Creating one form iteration procedure containing all the different activities that normally belong to another class within that "centralised" procedure, that could be better then (1) but I don't like it that much either.
Is there a better way of doing it using some .net functionality I don't master yet ?
Thanks for any advise.
Iterating through from controls can be tricky since controls are often nested. A more controlled approach would be to add another collection object to your form where you keep references to your added controls.....
e.g
Dim My_Widgets as New List(of Your-Control-Class-Name)
Then when you create the controls to the form also add them to that list.
My_Widgets.Add(Widget_Object)
After that it is a simple matter to iterate through that list.
For Each Widget as My_Widget_CLass in My_Widgets
' do what you need to do to Widget
Next
If you need to reference individual controls directly, use a dictionary object instead..
e.g.
Dim My_Named_Widgets as new Dictionary(of String, Your-Control-Class-Name)
Then add your control references to the dictionary by name
My_Named_WIdgets.add("<Whatever_You_USe_To_Identify_It>", Widget_Object)
You can then reference the specific control by the ID or name
My_Names_Widgets("ID").Property = Whatever '... etc
You seem to be indicating you have other controls for other purposes, as such it would be prudent to create similar collections for each type.
I have around 15 comboboxes on my form, all being loaded with the same information pulled from a table(~150 entries). Currently I am taking the information from the table, then looping through the entries and adding them to each textbox. I'm wondering if there's a more efficient way to load these comboboxes then having to individually add the table entry into each combobox, having to list 15 lines of code within the For loop.
I'm not seeing any performance issues with this, but figured I might as well work with the most efficient way possible rather than stick with what works. :)
You can create a list of the combo boxes, and then just loop through them. For instance:
Dim cbos() As ComboBox = {ComboBox1, ComboBox2, ComboBox3}
For Each cbo As ComboBox In cbos
' Load cbo from table
Next
Alternatively, if they are named consistently, you could find the combo box by name:
For i As Integer = 1 to 15
Dim cbo As ComboBox = DirectCast(Controls("ComboBox" & i.ToString())), ComboBox)
' Load cbo from table
Next
Since Combobox items are a collection, if their elements are the same, you can build and array with the objects you want to insert, and then just insert this array to each ComboBox with the method AddRange() (it's a method which exists inside the Combobox.items).
Getting an example from MSDN:
Dim installs() As String = New String() {"Typical", "Compact", "Custom"}
ComboBox1.Items.AddRange(installs)
Then you would only have to do a loop to add the array to each ComboBox. Of course, you will need to build your array first on your own, instead of this easy string array from the example.
Reference:
MSDN - AddRange
You could also do it this way since you mentioned that you already have a table.
Use a datatable
Change your table object into a datatable, which will assist in binding to the comboboxes. It might help if you add the datatable to a dataset too. That way you can attach all ComboBoxes (which are UI elements that let users see information) to the same DataSource, which is the datatable, in the dataset.
Binding
Now all you need to do is loop through all the comboboxes and set the datasource to the same table, that is if you decide to do it programmatically like so:
ComboBox1.DataSource = ds.Tables(0)
ComboBox1.ValueMember = "au_id"
ComboBox1.DisplayMember = "au_lname"
A further tutorial on this with the example above is found here
You can then also get the user selected value with ComboBox1.selectedValue.
On the other hand, if you did this with C# WPF, you can bind each comboBox in the XAML directly, I am unsure if this can be done in VB.net as I tried to look for the option but did not manage to do so, something you might want to try though.
Some very useful tutorials and guides on Data binding, which you might be interested:
~ denotes recommended reading for your question
MSDN: Connect data to objects
DotNetPerls on DataGridView (note this isn't a combobox, just displaying values)
~ VBNet DataTable Usage from DotNetPerls (this is in relation to 1.)
~ SO Q&A on Binding a comboBox to a datasource
Concepts of Databinding