Update a table using SqlAdapter - vb.net

I am developing an application where it displays a table that I have on the server and I would like the user to update it (insert/delete/update) directly within the application.
I created a telerik RadGridView named definitionView to display the data and I am following the instructions given directly from the Telerik Documentation: Updating the Database with ADO.NET
However I am stuck with the first part: Updating the database when the current row is changed
I tried to adapt the code shown in the example to my code but I keep getting an error on the adapter.Update() statement.
Public Class definitionSolution
Private lastEditRow As DataRow = Nothing
Private bindingSource
Public Sub New()
InitializeComponent()
Dim bindingSource As New BindingSource
Dim dsSolution As New DataSet()
adapter.Fill(dsSolution, "MyTable")
bindingSource.DataSource = dsSolution.Tables("MyTable")
definitionView.DataSource = bindingSource
AddHandler bindingSource.CurrentChanged, AddressOf DefinitionView_CurrentChanged
End Sub
Private Sub AutoSavingDataBSEventsForm_Load(ByVal sender As Object, ByVal e As EventArgs)
' TODO: This line of code loads data into the 'nwindDataSet.Employees' table. You can move, or remove it, as needed.
Dim dsSolution As New DataSet()
adapter.Fill(dsSolution, "MyTable")
bindingSource.DataSource = dsSolution.Tables("MyTable")
Dim current As Object = bindingSource.Current
If current IsNot Nothing Then
Me.lastEditRow = (CType(current, DataRowView)).Row
End If
End Sub
Private Sub DefinitionView_CurrentChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim dataRow As DataRow = CType(CType(sender, BindingSource).Current, DataRowView).Row
If lastEditRow IsNot Nothing AndAlso lastEditRow.RowState = DataRowState.Modified Then
adapter.Update(lastEditRow)
End If
lastEditRow = dataRow
End Sub
End Class
SQLDataAdapter is initialized in another module as follow:
Public queryString = "SELECT * FROM [dbo].Mytable"
Public adapter As New SqlDataAdapter(queryString, DB_CONNECTION)
The error is the following:
Error BC30518 Overload resolution failed because no accessible 'Update' can be called with these arguments:
- Public Overrides Function Update(dataSet As DataSet) As Integer': Value of type 'DataRow' cannot be converted to 'DataSet
- Public Overloads Function Update(dataRows As DataRow()) As Integer': Value of type 'DataRow' cannot be converted to 'DataRow()
- Public Overloads Function Update(dataTable As DataTable) As Integer': Value of type 'DataRow' cannot be converted to 'DataTable
Does anybody has an idea on how to solve this issue?
Also from their doc:
Let's assume that we have an ADO.NET DataTable that loads its data from a SqlDataAdapter and it is bound to a BindingSource component. Further, the BindingSource component is bound to RadGridView control.
I understand that I have a DataSet from SqlDataAdapter that is bound to a BindingSource component but I miss the last bit. What does it mean to bound a BindingSource to the RadGridView control?
Edit after #jmcilhinney comments
Switching from adapter.Update(lastEditRow) to adapter.Update(dsSolution) gives me the following error:
System.Reflection.AmbiguousMatchException: 'Overload resolution failed because no Public 'Update' is most specific for these arguments:
'Public Overrides Function Update(dataSet As System.Data.DataSet) As Integer':
Not most specific.
'Public Function Update(dataRows As System.Data.DataRow()) As Integer':
Not most specific.
'Public Function Update(dataTable As System.Data.DataTable) As Integer':
Not most specific.'
Switching from adapter.Update(lastEditRow) to adapter.Update(lastEditRow.ItemArray) gives me the following error:
System.InvalidCastException: 'Unable to cast object of type 'System.Object[]' to type 'System.Data.DataRow[]'

Your data adapter's Update method accepts multiple rows and performs inserts, updates and deletes as required. That Update method is overloaded and it will accept a DataRow array, so you can put your single row into an array and pass that:
adapter.Update({lastEditRow})
Otherwise, you need to pass the whole DataTable and let it pick out the row(s) that needs saving.

Related

How to enable multiple column for a listbox on VB.NET web application?

What i'm trying to do is to display two columns on a listbox so the user has more information.
The way i fill the listbox is by using a SqlDataSource with a custom query and then i attach that Data Source to the list box.
My problem is in the Data Source i can only pick two values one for the listbox display and the other values is to select the datafield value for the list box.
How can i display multiple column values from a SqlDataSource on a Listbox?
First create a Class for your data. I added a parameterized constructor so it would be easy to create a Coffee without separately setting properties. I also overrode the .ToString method so the ListBox would display what I want. If you really want columns you get into padding to a set length.
Public Class Coffee
Public Property Name As String
Public Property Type As String
Public Sub New(cofName As String, cofType As String)
Name = cofName
Type = cofType
End Sub
Public Overrides Function ToString() As String
Return $"{Name}, {Type}"
End Function
End Class
To fill the list, create a new coffee and add it to the list.
Private CoffeeList As New List(Of Coffee)
Private Sub FillCoffeeList()
Using cn As New SqlConnection(My.Settings.CoffeeConnection),
cmd As New SqlCommand("Select Top 10 Name, Type From Coffees;", cn)
cn.Open()
Using reader = cmd.ExecuteReader
While reader.Read
Dim c As New Coffee(reader.GetString(0), reader.GetString(1))
CoffeeList.Add(c)
End While
End Using
End Using
End Sub
Then in the Page.Load
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If Not IsPostBack Then
FillCoffeeList()
ListBox1.DataSource = CoffeeList
ListBox1.DataBind()
End If
End Sub
The ListBox calls .ToString on each Coffee object in CoffeeList and displays what we determined in the Class.

How to return specific properties of a custom vb.net object

I'm trying to generate a list of all of the TableName and FieldName properties for a custom object type called LxTextBox. I've gotten as far as generating a list of all of the LxTextBox names on my form, but I can't figure out a way to call the properties of the custom object... I've been looking into System.Reflection, but I haven't ever used it. Additionally, I'm returning the list to a RichTextBox while I'm testing this out, but ultimately, I need to return each objects properties as a data row. Example:
ObjectName Table Field
---------------------------------------
LxTextBox23 SomeTbl SomeFld
Here's my code to return the list - updated based on #OneFineDay...
Imports System.Collections.Generic
Imports Application.UDF.Controls
Public Class MeasurementsControl
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim textBoxList As New List(Of Control)
Dim customTbs = GetAllControls(Me)
Dim sb As New System.Text.StringBuilder
For index As Integer = 0 To customTbs.Count - 1
sb.Append(customTbs.Item(index).TableName & "." & customTbs.Item(Index).FieldName & System.Environment.NewLine)
Next
RichTextBox1.Text = sb.ToString
End Sub
Private Function GetAllControls(ByVal searchWithin As Control) As List(Of LxTextbox)
Dim returnList As List(Of LxTextbox) = Nothing
If searchWithin.HasChildren Then
returnList = searchWithin.Controls.OfType(Of LxTextbox).ToList
For Each ctrl As Control In searchWithin.Controls
returnList.AddRange(GetAllControls(ctrl))
Next
End If
Return returnList
End Function
End Class
I made the changes suggested and I'm throwing an error: OfType is not a member of System.Windows.Forms.Control.ControlCollection
FYI - Adding Imports System.Linq did not fix the error.
You are boxing it into a Control the object from where it derives, where you're custom properties cannot be found. You can cast it right from the control collection.
Dim customTbs = GetAllControls(Me)
'recursive function
Private Function GetAllControls(ByVal searchWithin As Control) As List(Of LxTextbox)
Dim returnList As List(Of LxTextbox) = Nothing
returnList = searchWithin.Controls.OfType(Of LxTextbox).ToList
If searchWithin.HasChildren Then
For Each ctrl As Control In searchWithin.Controls
Dim ctrls = GetAllControls(ctrl)
If Not ctrls Is Nothing Then returnList.AddRange(ctrls)
Next
End If
Return returnList
End Function

Create and loop through collection subset of controls

Im making a small vb.net windows form application in which I have 4 ComboBoxes. I would like to add the ComboBoxes to a collection and be able to loop through that collection to refer to each one.
There are other ComboBoxes on the form so I cannot just use the collection for the entire form (the form layout cannot be changed, e.g. to add a container, etc).
I was thinking something like the following:
Public Class Form1
Dim IoTypeCombos As New ControlCollection(Me) From {Me.IO1_ComboBox, Me.IO2_ComboBox, Me.IO3_ComboBox, Me.IO4_ComboBox}
Dim IoTypes As New Collection() From {"Out 0", "Out 1", "Input", "Analog"}
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For Each cb As combobox In Me.IoTypeCombos
FillComboBox(cb, Types)
Next
End Sub
Function FillComboBox(cb As Control, cc As Collection) As Boolean
Dim cbc As ComboBox = CType(cb, ComboBox)
If cc.Count = 0 Then
Return False
End If
For Each cn In cc
cbc.Items.Add(cn)
Next
Return True
End Function
This doesn't raise any exception, BUT it doesn't populate the ComboBoxes either :(
The FillComboBox() works perfectly if I pass a single control to it.
What am I doing wrong? Thanks
This line is illegal:
Public Class Form1
Dim IoTypeCombos As New ControlCollection(Me) From {Me.IO1_ComboBox,
Me.IO2_ComboBox, Me.IO3_ComboBox, Me.IO4_ComboBox }
That code will run before the constructor, before Me or ION_ComboBox exist. In this case, the resulting collection contains nothing since there is nothing to put in it yet.
In other cases, referencing controls before they exist can result in a NullReference being thrown, but due to an odd bug it may not be reported. When that happens, the rest of the code is skipped and the form simply shown.
In either case, the solution is to declare your collection at the form level, but populate it in the form load event once the controls do exist. I would also use a Collection(Of T) instead (an array or List(Of T) will also work, the OP uses/asks about a collection though):
Imports System.Collections.ObjectModel
Public Class Form1
Dim IoTypeCombos As Collection(Of ComboBox) ' form and controls Do No Exist yet
Public Sub New
'...
InitializeComponent()
' NOW they exist
End Sub
Sub Form_Load
IoTypeCombos = New Collection(Of ComboBox)
IoTypeCombos.Add(IO1_ComboBox)
IoTypeCombos.Add(IO2_ComboBox)
...
If you use a List(Of ComboBox), you can populate it different ways:
' in the ctor:
IoTypeCombos = New List(Of ComboBox)({IO1_ComboBox, IO2_ComboBox...})
' using AddRange:
IoTypeCombos.AddRange({IO1_ComboBox, IO2_ComboBox...})
Not sure if you need the where clause, but if you have other comboboxes that do not have names like this and do not want them in the collection then you do need it.
Dim IoTypeComboboxes =
Me.Controls.OfType(Of Combobox)().Where(Function(cb) cb.Name.StartsWith("IO")).ToList()
'on yourFormName
'added :
'45 PictureBox:("PicBarNum1_NotLastOdig" to "PicBarNum45_NotLastOdig")
'added:
'45 PictureBox:("PicBarNum1_UkOdig" to "PicBarNum45_UkOdig")
Public Class yourFormName
Private picbarlistNum1to45_UkOdig As New List(Of PictureBox)
Private picbarlistNum1to45_UkLastNotOdig As New List(Of PictureBox)
Private sub yourFormName_Load
Call AddPicBoxesInList_OdigNoOdig()
End sub
Private Sub AddPicBoxesInList_OdigNoOdig()
picbarlistNum1to45_UkOdig.Clear()
picbarlistNum1to45_UkLastNotOdig.Clear()
picbarlistNum1to45_UkOdig = Me.Controls(0).Controls.OfType(Of PictureBox)()
.Where(Function(pb) pb.Name.StartsWith("PicBarNum") And
pb.Name.EndsWith("_UkOdig")).ToList()
picbarlistNum1to45_UkLastNotOdig = Me.Controls(0).Controls.OfType(Of
PictureBox)().Where(Function(pb) pb.Name.StartsWith("PicBarNum") And
pb.Name.EndsWith("_NotLastOdig")).ToList()
End Sub
End Class

Binding data to a combobox and add a select option

I'm using VB.NET and Visual Studio 2010
I've got a windows form with a combobox.
I fill the combobox using the following
Dim objSizes As List(Of ASME_Hub_Sizes) = ASME_Hub_Sizes.GetAllHubSizes()
If Not objSizes Is Nothing Then
With Me.cboSize
.DisplayMember = "Size"
.ValueMember = "ID"
.DataSource = objSizes
End With
End If
This works fine, but i would like to add a "Select Size..." option but i'm unsure how to do this.
It seems so much easier to do this in asp.net, but this has me baffled
Thanks
Mick
You could try adding a custom objSize object to the objSizes collection that has ID = 0 and value = "Select size..." as it's ID 0 it should be at the top (I think) and won't clash with any values in your database, upon saving the record you can validate the combobox to avoid writing the "Select size..." object to your database. I'll have a bit of a code and see if this will work...
Ok, I've had another look. You can do as I suggested but you must sort the list before passing it to the combobox. Here is my example:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
With Me.ComboBox1
.DisplayMember = "Description"
.ValueMember = "ID"
.DataSource = GetListOfObjects.returnListOFObjects
End With
End Sub
End Class
Public Class dummyObjectForCombo
Public Property ID As Integer
Public Property Description As String
Public Sub New(ByVal id As Integer,
ByVal description As String)
_ID = id
_Description = description
End Sub
End Class
Public Class GetListOfObjects
Public Shared Function returnListOFObjects() As List(Of dummyObjectForCombo)
Dim col As New List(Of dummyObjectForCombo)
Dim obj0 As New dummyObjectForCombo(-1, "Herp")
Dim obj1 As New dummyObjectForCombo(1, "Jamie")
Dim obj2 As New dummyObjectForCombo(2, "Bob")
col.Add(obj1)
col.Add(obj2)
col.Add(obj0)
'using a lambda to sort by ID as per http://stackoverflow.com/questions/3309188/c-net-how-to-sort-a-list-t-by-a-property-in-the-object
Return col.OrderBy(Function(x) x.ID).ToList
End Function
End Class
I've used -1 as the topmost record instead of 0.
So you'd get your list as usual, add in the extra dummy record, then sort it as per the above code before assigning it as your combo boxes datasource.
simply add the item before setting the datasource property
C# : cboSize.items.add(...);

DataBinding a Combobox to custom object fails to show data

I'm having a problem with databinding an object to a combobox in VB.NET (VS2008/.NET 3.5). Please take a look at this simplified version of my code:
Friend Class clDocument
Private _items as New List(Of clDocumentItems)
<System.ComponentModel.DisplayName("Items")> _
<System.ComponentModel.Bindable(True)> _
Public Property Items() As List(Of clDocumentItems)
Get
Return _items
End Get
Set(ByVal value As List(Of clDocumentItems))
_items = value
RaiseEvent ItemsChanged(Me, New EventArgs)
End Set
End Property
Public Event ItemsChanged As EventHandler
End Class
Friend Class clDocumentItems
Private _uid as String = ""
Private _docnumber as String = ""
<System.ComponentModel.DisplayName("UID")> _
<System.ComponentModel.Bindable(True)> _
Public Property UID() As String
Get
Return _uid
End Get
Set(ByVal value As String)
_uid = value
RaiseEvent UIDChanged(Me, New EventArgs)
End Set
End Property
<System.ComponentModel.DisplayName("Document")> _
<System.ComponentModel.Bindable(True)> _
Public Property DocNumber() As String
Get
Return _docnumber
End Get
Set(ByVal value As String)
_docnumber = value
RaiseEvent DocNumberChanged(Me, New EventArgs)
End Set
End Property
Public Event UIDChanged As EventHandler
Public Event DocNumberChanged As EventHandler
End Class
Somewhere else, we got this code:
Private Sub cmd_go_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_go.Click
'Try to load the object with data, this works well
Dim _document as New clDocument
_document.Load(somevalue)
cmb_docs.DataSource = Nothing
cmb_docs.Items.Clear()
If _document.UID = "" Then Exit Sub 'Object wasn't loaded so get out
'Create the binding.
cmb_docs.ValueMember = "UID"
cmb_docs.DisplayMember = "DocNumber"
cmb_docs.DataSource = _document.Items
End Sub
Now, the problem is that the ComboBox is populated with as many items as there are objects in _document.Items, but it doesn't passes real data -The combobox is filled with "Namespace.clDocumentItems" strings. Please note that similar code works perfectly when bound to regular class properties (String, integer, etc).
Now, I can guess by using the debugger's reflection that it is because the Datsource is receiving a List of objects instead of fields, but then again I don't know how to avoid that without having to create another Array or List with just those values and passing THAT to the Datasource property...
I explored the site for something similar, the only thing that came close was this question that went unanswered 3 years ago, so I hope to have better luck today ;)
Thanks for your time!
EDIT: Below I add the code I used for databinding to a DataGridView, as requested in the comments.
Private WithEvents _bs as New BindingSource
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.AutoGenerateColumns = False
Dim column As DataGridViewColumn = New DataGridViewTextBoxColumn()
column.DataPropertyName = "Document"
column.Name = "colDoc"
DataGridView1.Columns.Add(column)
_bs.DataSource = _document.Items
Me.DataGridView1.DataSource = _bs
End Sub
There is actually nothing at all wrong with your code as you have it written above (I copied it into a new WinForms app, supplied some default values, and it worked correctly).
There are two possible reasons that your implementation may not be working:
If there is a typo in DisplayMember.
If the access level of the DisplayMember property prevents the
combobox from accessing it.
If the property cannot be found or accessed, .Net drops back to the default implementation of using the object's ToString method. So one quick and dirty fix would be to override the ToString method of clDocument and return DocNumber. That should resolve the display issue, but not the underlying cause of the problem, which will require a little more research.
ok, The problem was the comboBox was faulty. Removing the control from the form and adding it again solved the problem. I accept the answer because it contains useful information.
Thanks