I am using DataSet/DataTable adapters to retrieve data from my database.
Now I need a list of suppliers to my dropdown but unfortunately it is empty all the time, even if I catch with a breakpoint that there are some results.
Here is my code:
Dim riLookup As New RepositoryItemLookUpEdit()
riLookup.NullText = String.Empty
riLookup.DataSource = DataTableDobTableAdapter.FillDob(Me.DsOrders.DataTableDob)
riLookup.ValueMember = "ID"
riLookup.DisplayMember = "TITLE"
riLookup.BestFitMode = DevExpress.XtraEditors.Controls.BestFitMode.BestFitResizePopup
GridView1.Columns("Code").ColumnEdit = riLookup
What I see when I am debugging:
First of all I dont know why is integer writter there,
and when I continue with debugging and apps run there are empty values:
EDIT:
I never before worked with v.b and devexpress controles so all of this is very confusing to me..
# ED when I rightclick on my method and choose "Go To Definition" I am seeing this:
Public Overloads Overridable Function FillDob(ByVal dataTable As dsOrders.DataTableDobDataTable) As Integer
Me.Adapter.SelectCommand = Me.CommandCollection(0)
If (Me.ClearBeforeFill = true) Then
dataTable.Clear
End If
Dim returnValue As Integer = Me.Adapter.Fill(dataTable)
Return returnValue
End Function
I can see there As Integer but why is that if I can see on data preview my real columns from database and neither of them is Integer.. I am really confused here :/
The fill method on the adapter fills the DataTable and returns the count of rows that it filled the DataTable with. It's right there in the code you showed me for the fill method:
Dim returnValue As Integer = Me.Adapter.Fill(dataTable)
Return returnValue
Me.Adapter.Fill(dataTable). Then the DataTable has rows in it.
The rows are in the DataTable. Use the DataTable as the data source.
Dim riLookup As New RepositoryItemLookUpEdit()
riLookup.NullText = String.Empty
DataTableDobTableAdapter.FillDob(Me.DsOrders.DataTableDob)
riLookup.DataSource = Me.DsOrders.DataTableDob
riLookup.ValueMember = "ID"
riLookup.DisplayMember = "TITLE"
riLookup.BestFitMode = DevExpress.XtraEditors.Controls.BestFitMode.BestFitResizePopup
GridView1.Columns("Code").ColumnEdit = riLookup
Related
I am trying to upload a csv file that has two records in it.
The below code executed for two times and third time I got this exception----Conversion of type string " " to double not valid
I put a debugger where I found the values of two colums of excel sheet but third time I am getting this exception. Your help is highly appreciated.
Below is the code.
Public Function GetLocationInformation(stream As Stream) As List(Of CsvPropLocation) _
Implements ICsvHandling.GetLocationInformation
If stream Is Nothing Then Return Nothing
Dim locations = New List(Of CsvPropLocation)
Using reader = New StreamReader(stream)
Dim config = New CsvConfiguration(CultureInfo.InvariantCulture) With {
.HasHeaderRecord = True,
.IgnoreBlankLines = False
}
Using csv = New CsvReader(reader, config)
Using dataReader As New CsvDataReader(csv)
Dim dt = New DataTable()
dt.Load(dataReader)
For Each row As DataRow In dt.Rows
Dim propLocation As CsvPropLocation
'find or create a propLocation
If locations.Any(Function(x) x.nLocationNumber = row("LocNum")) Then ######Got exception here ######
propLocation = locations.First(Function(x) x.nLocationNumber = row("LocNum"))
Else
propLocation = New CsvPropLocation(row("LocNum"))
locations.Add(propLocation)
End If
'do building stuff.
Dim building = ParseRowIntoBuilding(row)
propLocation.AddBuilding(building)
Next
End Using
End Using
End Using
Return locations
End Function
Change your line to
Dim number As Double
If Double.TryParse(row("LocNum"), number ) AndAlso locations.Any(Function(x) x.nLocationNumber = number )
This way you make sure number will be evaluated only if it gets a valid value from row("LocNum")
Also keep in mind the Else part must be controlled as New CsvPropLocation(row("LocNum")) probably is expecting a valid Double which isnt inside locations so, change to:
Else If Double.TryParse(row("LocNum"), number ) 'You can check against number = 0
'if zero isn't a valid value for number
'(or initialize number to a known invalid value and check against it)
'if yuo didn't want a double try parse
propLocation = New CsvPropLocation(number)
locations.Add(propLocation)
End If
I have some code I have used many times over which has always worked great for me. The latest use, however, throws an exception under certain circumstances that I cannot seem to resolve. Here it is:
I read from a text file to an array, use it as a binding source for some of my controls (it autofills 3 controls based on the selection of a single control). I created a Student class with 4 properties (Name, ID, DOB and DOE). Here is the code I use:
Private Sub autoFill()
Dim rost As String = "Roster.txt"
Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
Dim list As List(Of Student) = New List(Of Student)
For i As Integer = 0 To lines.Count - 1
Dim data As String() = lines(i).Split(":")
list.Add(New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
})
Next
StudentBindingSource.DataSource = list
End Sub
Now here is the problem. In the "For" loop when I set i to 0 to lines.count -1 it throws this error:
VB>NET EXCEPTION
However...If I change i to 1 instead of 0 it works OR if I take away data(2) and data(3) it works with i = 0. I would prefer to use 0 so that I can have a blank line in the combobox or "--choose--", etc. The only thing I have thought that might be useful is that my first row in the text file has nothing to split. Here is the line format of the text file:
Student Name ID# DOB DOE <-----This header row is NOT in the text file
Last Name, First Name : 0000000 : 01/01/2021 : 01/01/2021
I'm going to assume I'm missing something really simple here. Any guidance would be greatly appreciated! Thank you.
Before we get to the actual problem, let's re-work some things.
A better way to structure code, especially when working with data loading, is to have a method that accepts an input and returns a result. Additionally, calling ToList() or ToArray() is a very expensive operation for performance. Very often you can improve performance dramatically by working with a lower-level IEnumerable for as long as possible.
With those principles in mind, consider this code:
Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
Dim lines As IEnumerable(Of String) = File.ReadLines(fileName)
Return lines.
Select(Function(line) line.Split(":")).
Select(Function(data)
Return New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
}
End Function)
End Function
Private Sub autoFill()
StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub
Now on to the actual issue. The problem was not from looping through the list variable. The problem is the data array. At some point you have a line that doesn't have enough elements. This is common, for example, as the last line in a file.
There are many ways to address this. In some cases, the exception is already the appropriate result, because if you have bad data you really don't want to continue. In other cases you want to log the bad records, perhaps to a report you can easily review later. Or maybe you just want to ignore the error, or pre-filter for rows with the right number of columns. Here is an example of the last option:
Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
Return File.ReadLines(fileName).
Select(Function(line) line.Split(":")).
Where(Function(data) data.Length = 4).
Select(Function(data)
Return New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
}
End Function)
End Function
Private Sub autoFill()
StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub
The problem is that you didn't check 'data' to have enough elements to create the 'Student'. A simple check should fix it.
Private Sub autoFill()
Dim rost As String = "Roster.txt"
Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
Dim list As List(Of Student) = New List(Of Student)
For i As Integer = 0 To lines.Count - 1
Dim data As String() = lines(i).Split(":"c)
'Check data
If data.Length >= 4 Then '
list.Add(New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
})
End If
Next
StudentBindingSource.DataSource = list
End Sub
try this code:
Dim list As List(Of Student) = New List(Of Student)(100)
basically initialize the student list with a capacity. This is the capacity of the list, not the count/length.
DataGridView caught me again, I cannot figure out, why I get cell formatting error with following code. None of the solutions I found on the net wouldn't work/fit either. On load I set:
Dim dtAlign As New DataTable ' creating and filling a DataTable
dtAlign.Columns.Add("ID", GetType(Int32))
dtAlign.Columns.Add("Text", GetType(String))
dtAlign.Rows.Add(1, "Left")
dtAlign.Rows.Add(2, "Right")
dtAlign.Rows.Add(3, "Center")
Dim cola As DataGridViewComboBoxColumn = CType(Me.dgList.Columns("ColAlign"), DataGridViewComboBoxColumn)
cola.DisplayMember = "Text"
cola.ValueMember = "ID"
cola.DataSource = dtAlign ' assign datatable as a combobox col. datasource
The columns are set via VS GUI (this column: Name = 'ColAlign', Width = 100, DataPropertyName = 'ColAlign', column type = DataGridViewComboBoxCell, etc.).
It, works, at a breakpoint just before filling data into DGV, I see a valid datatable is provided:
When I don't load any data into column, I can see a proper ComboBox selection:
However, if I add data in the datasource for this column, I get cell formatting error (saying the value is not valid) and the value is shown as display member text:
The database column is not nullable (at this point always 1), and is INT. I even tried to CAST it, to be sure it's not mixed up i.e. as string:
CAST(ColAlign as INT) as ColAlign
Still, I get the error and I have no more ideas what can be wrong, but ovbiously the 1 in the datatable is not the same as 1 in the database result set. In past I had a problem with Int16 not matching INT, but Int32 always worked agaist INT in database. And even:
CAST(1 as INT) as ColAlign
...doesn't work. By the way, I assign the data simply this way:
Me.dgList.DataSource = ds.Tables(0)
As usually, it has to be something really simple, what I'm missing. I would appreciate even hints how to furthermore debug such an issue.
EDIT:
I also tried creating a button and in onClick wrote a code:
Me.dgList.Rows(1).Cells("ColAlign").Value = 1
This works well.
EDIT 2:
I inserted a DataTable between DataSet and DataSource with fixed datatypes columns (int32 in case of the ComboBoxColumns), which should rule out that wrong datatypes are provided and it still doesn't work...
Dim dtGrid As New DataTable
dtGrid.Columns.Add("ID", GetType(Int32))
dtGrid.Columns.Add("FormID", GetType(Int32))
dtGrid.Columns.Add("ColName", GetType(String
dtGrid.Columns.Add("IsVisible", GetType(Boolean))
dtGrid.Columns.Add("ColWidth", GetType(String))
dtGrid.Columns.Add("ColAlign", GetType(Int32))
dtGrid = ds.Tables(0)
Me.dgList.AutoGenerateColumns = False
Me.dgList.DataSource = dtGrid
EDIT 3
Another debugging:
Dim dtTemp As DataTable
Dim dgwcb As DataGridViewComboBoxColumn = CType(Me.dgList.Columns("ColAlign"), DataGridViewComboBoxColumn)
dtTemp = CType(dgwcb.DataSource, DataTable)
MsgBox("ValueMember name = " & dgwcb.ValueMember.ToString & vbCrLf &
"DisplayMember name = " & dgwcb.DisplayMember.ToString & vbCrLf &
"DataPropertyName = " & dgwcb.DataPropertyName.ToString & vbCrLf &
"Value = " & Me.dgList.Rows(2).Cells("ColAlign").Value.ToString & vbCrLf &
"ToString = " & dgwcb.ToString)
dtTemp in DataSet Visualizer looks good and everything checked in MsgBox is es expected (ValueMember = "ID", DisplayMember = "Text", DataPropertyName = "ColAlign", Value = 2 /I set it to 2 for a change/).
WORKAROUND:
The only way it works is to leave columns with ComboBoxCell empty and fill them manually after the DGV datasource is set, narrowing them to Int32 along (note that they were narrowed both in SQL and dtGrid already):
For ir = 0 To dtGrid.Rows.Count - 1
Me.dgList.Rows(ir).Cells("ColAlign").Value = CInt(dtGrid.Rows(ir)("ColAlign"))
Next
Since I'm using DGV with ComboBoxCell extremely rarely, I can live with this "solution".
EDIT 4 / WORKAROUND 2
I created a 2nd, identical (structure) dtGrid2 and copied values row-by-row and cell-by-cell into the 2nd and voila - it works with the dtGrid2 and doesn't with the original dtGrid! So when I pull data from database, the original correct datatypes of columns are re-typed to something wrong. I suspect this is only happening with SQLiteDataAdapter, because I didn't experienced it with SqlDataAdapter in past. A simplified code to explain:
Dim dtGrid As New DataTable
Dim dtGrid3 As New DataTable
dtGrid.Columns.Add("ID", GetType(Int32))
dtGrid.Columns.Add("ColName", GetType(String))
dtGrid.Columns.Add("ColAlign", GetType(Int32))
' load data from DB. ...and corrupt the dtGrid...
dtGrid = ds.Tables(0).DefaultView.ToTable
dtGrid3.Columns.Add("ID", GetType(Int32)) ' identical columns
dtGrid3.Columns.Add("ColName", GetType(String)) ' identical columns
dtGrid3.Columns.Add("ColAlign", GetType(Int32)) ' identical columns
For ir = 0 To dtGrid.Rows.Count - 1 ' copy all values to new identical table
dtGrid3.Rows.Add({dtGrid(ir)("ID"), dtGrid(ir)("ColName"), dtGrid(ir)("ColAlign")})
Next
Me.dgList.DataSource = dtGrid3 ' works!!! Doesn't with dtGrid...
Try this:
Dim cola As DataGridViewComboBoxColumn = CType(Me.dgList.Columns("ColAlign"), DataGridViewComboBoxColumn)
cola.DataSource = dtAlign
cola.DataPropertyName = "ID"
cola.DisplayMember = "Text"
cola.ValueMember = "ID"
You need to set DataPropertyName if you are binding to DataSource like DataTable
You have a DataGridView with some columns set.
Something like this:
But could be anything else.
Let's create a sample DataSource using a List(Of Class):
Public Class MyDataSourceRow
Private _ID As Integer
Private _Text As String
Public Sub New()
End Sub
Public Property ID() As Integer
Get
Return Me._ID
End Get
Set(ByVal value As Integer)
Me._ID = value
End Set
End Property
Public Property Text() As String
Get
Return Me._Text
End Get
Set(ByVal value As String)
Me._Text = value
End Set
End Property
End Class
Creeate a new DataGridViewComboBoxColumn, set it's basic properties, specify a DataSource and add it to the DataGridView:
Dim MyDataSource = New List(Of MyDataSourceRow)
MyDataSource.Add(New MyDataSourceRow With {.ID = 1, .Text = "Left"})
MyDataSource.Add(New MyDataSourceRow With {.ID = 2, .Text = "Right"})
MyDataSource.Add(New MyDataSourceRow With {.ID = 3, .Text = "Center"})
Dim MyColumn As DataGridViewComboBoxColumn = New DataGridViewComboBoxColumn
MyColumn.Width = 150
' Name of the new Column. Will also be the text of the Header
MyColumn.Name = "ComboAlignment"
'Define its DataSource
MyColumn.DataSource = MyDataSource
' The DataPropertyName is the field of your DataSource to which your column value is bound
MyColumn.DataPropertyName = "ID"
' This is the value you want the User to see
MyColumn.DisplayMember = "Text"
' ValueMember is the value passed to the DataGrid when a User selects an entry in the DropDown
MyColumn.ValueMember = "ID"
'Insert the column in the first position -> Index(0)
Me.DataGridView1.Columns.Insert(0, MyColumn)
Now, this is the result:
For some reason, you are confusing the .Name of the column with it's .DataPropertyName
I've been working on a project which has a Function of reading Data from a DataTable and returning it as a list. I made specific statements over some rows to get the data I want.
Little problem is, my entity "Number" is declared As an Integer and in the DataTable I do have some String values which leads the function to crash. Do any of you guys has an Idea about how I can check which Data Type the row "Number" has and if it's not an Integer to just leave it out?
My function looks like this:
Public Function LiefereAlleRechte(ByVal dt As DataTable) As ICollection(Of Recht) Implements IBenutzerInfoServiceUtil.LiefereAlleRechte
If dt Is Nothing Then
Throw New ArgumentNullException("DataTable can't be empty", "dt")
End If
Dim query = From dr As DataRow In dt.DefaultView.ToTable(True, "Name", "Number")
Dim coll As ICollection(Of Recht) = New List(Of Recht)
For Each row In query
Dim recht As Recht = New Recht()
With recht
.Name = row.Item("Name")
.Nummer = row.Item("Number")
coll.Add(recht)
End With
Next
Return coll
End Function
Thanks for any help!
Since i needed to disable (grey out) some items inside a ListBox, i'm using a Custom control that can be found here:
Here is my current code:
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtp.Columns.Add("key")
dtp.Columns.Add("value")
PopulateDataTable(dtp, "myTxt")
_dataView = New DataView(dtp)
'Custom ListBox
List1.ValueMember = "key"
List1.DisplayMember = "value"
List1.DataSource = _dataView
'Legacy ListBox
List2.ValueMember = "key"
List2.DisplayMember = "value"
List2.DataSource = _dataView
UpdateLanguageMenu()
End Sub
Private Function PopulateDataTable(dt As DataTable, resTxt As String)
Using sw As New StringReader(My.Resources.ResourceManager.GetObject(resTxt))
Do
Dim line As String = sw.ReadLine
If line Is Nothing OrElse line.Trim = String.Empty Then Exit Do
Dim strArr() As String
strArr = line.Split(",")
Dim row As DataRow = dt.NewRow()
row("key") = strArr(0)
row("value") = strArr(1)
dt.Rows.Add(row)
Loop
sw.Close()
End Using
End Function
List1 is the Custom ListBox and List2 is the ListBox that comes with VS2012E.
I don't need List2, it's only there to test,
and at runtime, in List2 i get all my values loaded correctly, instead in List1 i get System.Data.DataRowView in all rows..
The strange thing is that, my txt i'm loading is like:
00A1,MyValue1
00A2,Myvalue2
00A3,MyValue3
I have also a Label, and when selecting items on the ListBox i have code to change the Label.Text to List.SelectedValue that is the first part before the comma.
And it get displayed in the label. Only items inside the Custom ListBox are not being displayed.
Populating List1 manually, instead using a DataTable, is working.
And since i'm a beginner i can't locate the problem.
I think your problem has to do with this line: string displayValue = GetItemText(item); in the control. This takes for granted that all items are strings. In your case it is a datarowview hence the result (drv.toString would return something like that). You need to convert "item" into a drv and set display value to be drvItem("value" or "key") instead. So it is basically not your code that is the problem, it is the control.
Actually... After reading the code in the control and not on the code project site, I realised that this line:
displayValue = GetItemText(item);
Doesn't even exist. It is exchanged with
item.ToString()
Which pretty much proves my theory.
Right, how to fix.
In:
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
You have this:
object item = this.Items[e.Index];
What you have to do is to convert item into a DataViewRow and assign value to a variable, something like this:
DataViewRow dvrItem = (DataViewRow)item;
String displayText = dvrItem("key"); or String displayText = dvrItem("value");
Then change all these:
e.Graphics.DrawString(item.ToString(), e.Font, SystemBrushes.GrayText, e.Bounds);
Into:
e.Graphics.DrawString(displayText, e.Font, SystemBrushes.GrayText, e.Bounds);