Editing Datable before binding to listview in vb.net - vb.net

hi this is my code to get datable from query but i need to check for some values like if there is 0 in any column then replace it with N.A.
Dim op As New cad
Dim dt As DataTable = op.Fetchbooks().Tables(0)
Dim sb As New StringBuilder()
Dim rp As System.Data.DataRow
If dt.Rows.Count > 0 Then
ListView1.DataSource = dt
ListView1.DataBind()
DropDownList1.DataSource = dt
DropDownList1.DataTextField = "Description"
DropDownList1.DataValueField = "Description"
DropDownList1.DataBind()
End if
so is there any way to check some values and edit in datable before binding ???

First, if possible i would modify your sql-query in Fetchbooks instead to replace 0 with N.A.. I assume you are querying the database.
However, if you want to do it in memory:
For Each row As DataRow In dt.Rows
For Each col As DataColumn In dt.Columns
If row.IsNull(col) OrElse row(col).ToString = "0" Then
row(col) = "N.A."
End If
Next
Next

Sure: you can iterate through the table, making whatever value replacements are appropriate (assuming that your replacement values are type-compatible with what came from the query).
Something like:
For Each row as DataRow in dt.Rows
if row("columnname") = "left" then
row("columnname") = "right"
Next
Then bind it to the grid, and you should see your updated values.

Once you have the DataTable object you can manipulate it as you need:
For Each rp In dt.Select("COLUMN_A = '0'")
rp("COLUMN_A") = "N.A."
Next
Note that this assumes that COLUMN_A is defined as a string type, not a numeric.
The challenge will be if you intend on saving this data back to it's source and you don't want the original 0 value to be saved instead of N.A.. You could add dt.AcceptChanges immediately after the above loop so that it will appear as the Fetchbooks query had these values all along.

Related

How can I merge 2 DataView built in 2 different way?

I am not a c# developer and I found myself at work working with a huge C# application...hug..
Now I am trying to populate an existing DataGrid with some more data which has been 'created' in a different way...let me show you what I mean.
This is how the existing DataView is generated:
Dim lDataSet As System.Data.DataSet
Dim lSqlCommand As New System.Data.SqlClient.SqlCommand
Dim lConvert As New PeoplePlanner.Common.Data.Convert
lSqlCommand.CommandType = CommandType.StoredProcedure
lsqlCommand.CommandText = "AccessIntegrationEmployeeInboundSearch"
lDataSet = objDatabase.GetDataSet(lSqlCommand)
If Not IsNothing(lDataSet) Then
objDataView = lDataSet.Tables(0).DefaultView
End If
There is probably be stuff missing in that code but hopefully it is enough to get an overview. It uses Stored Procedure (SP) to get some data from the DB and it returns the result inside 'lDataSet' and then we do 'objDataView = lDataSet.Tables(0).DefaultView'.
Now the new data which I want to 'merge in' it has the same fields but it is not the response of a SP but of an operation I have created which returns back a List of OnBoardingEmployee(let's call it like that) and if I want to correctly show ONLY the data inside that list this is what I do:
Dim lDataView As System.Data.DataView
Dim op = CoreInjector.Inject(Of IGetAllDataHubIncomingMessagesToBeProcess).Execute()
lDataView = Common.Detail.DataGridOperationHelper.ConvertToDataTable(op.OnBoardingEmployee).DefaultView
objDataView = lDataView
Where:
op contains a list of OnBoardingEmployee which has the same fields as the existing table
lDataView basically is the same as objDataView that's why as last step I assign objDataView = lDataView
Now I would basically like to merge, join, add, whatever
The objDataView created for the first table:
objDataView = lDataSet.Tables(0).DefaultView
with the one I have created afterwards:
lDataView = Common.Detail.DataGridOperationHelper.ConvertToDataTable(x.OnBoardingEmployee).DefaultView
How do I do that? :'(
They have the same data structure or better say they use the same view.
Thanks for the help :)
I have got it working :) this is my implementation:
Dim employeeJSONTable As DataTable
Dim employeeExistingTable As DataTable
Dim myDataRow As DataRow
Dim employeeID As Integer
if Request.QueryString.Get("Function") = "HubInbound" then
Dim employeeJSONList = CoreInjector.Inject(Of IGetAllDataHubIncomingMessagesToBeProcess).Execute()
employeeJSONTable = Common.Detail.DataGridOperationHelper.ConvertToDataTable(employeeJSONList.OnBoardingEmployee)
employeeJSONTable.PrimaryKey = New DataColumn(){ employeeJSONTable.Columns("EmployeeID")}
End If
lDataSet = objDatabase.GetDataSet(lSqlCommand)
employeeExistingTable = lDataSet.Tables(0)
For Each row As DataRow In employeeExistingTable.Rows
employeeID = row.Item("EmployeeID")
myDataRow = employeeJSONTable.Rows.Find(employeeID)
if (myDataRow Is Nothing) then
employeeJSONTable.ImportRow(row)
End If
Next row
If Not IsNothing(employeeJSONTable.DefaultView) And Request.QueryString.Get("Function") = "HubInbound" Then
objDataView = employeeJSONTable.DefaultView
Elseif Not IsNothing(lDataSet) Then
objDataView = lDataSet.Tables(0).DefaultView
End if

converting dataset.Compute("Sum(TARGET_AREA)", "") to .toString("N")

I am trying to convert my computed database columns in my datagrid. I was able to compute the columns and wanted to fix the format of the results.
Label18.Text = dataset.Compute("Sum(TARGET_AREA)", "") & " (ha)"
An example of my output is 100000.00 (ha)
What I wanted for my output is to look like this 100,000.00 (ha)
I tried using .toString("N") but no luck.
my column type is Decimal and the others were Double.
Any idea on how to fix it?
You could use String.Format method.
Example
value = 1234.567890
Console.WriteLine(value.ToString("0,0.00", CultureInfo.InvariantCulture))
Source: MSDN Custom Numeric Format Strings.
Here is an example using a DataTable - Note that you may want to check the sum if the column allows nulls. Also, the sum here is invoked over the datatable object not the dataset (as in your question) - This code has been automatically translated from C# - I assume it syntactically OK.
Dim dataset As New DataSet("ds1")
Dim dt As New DataTable("dt")
Dim dc As DataColumn = dt.Columns.Add("TARGET_AREA", GetType(System.Decimal))
Dim dr As DataRow = dt.Rows.Add()
dr("TARGET_AREA") = 100000.0
Dim finalResult As String = ""
Dim value As Decimal
If dt.Rows.Count > 0 Then
Dim result_obj As Object = dt.Compute("Sum(TARGET_AREA)", "")
If result_obj Is System.DBNull.Value Then
value = 0
Else
value = Convert.ToDecimal(result_obj)
End If
finalResult = String.Format(value.ToString("0,0.00", System.Globalization.CultureInfo.InvariantCulture)) & " (ha)"
Console.WriteLine(finalResult)
End If
Console.Read()
Return

First row as header in datagridview

Imported data from CSV to datagridview has header in first row, I could hide that row and name header for every column, problem is that data table has 68 columns. Is it possible to make first row header without having to do that manually for every single column?
Your datagrid should have taken all column names from CSV, if not then you need to have a look at this great article. It will help you a lot. This is the link.
After experimenting and help from user: ooopsoft :
Dim TextFieldParser1 As New Microsoft.VisualBasic.FileIO.TextFieldParser(receiveStream)
TextFieldParser1.Delimiters = New String() {","}
Dim newline() As String = TextFieldParser1.ReadFields()
While Not TextFieldParser1.EndOfData
Dim Row1 As String() = TextFieldParser1.ReadFields()
If DataGridView1.Columns.Count = 0 AndAlso Row1.Count > 0 Then
Dim i As Integer
For i = 0 To Row1.Count - 1
DataGridView1.Columns.Add(newline(i), newline(i))
Next
End If
End While

Sort Alphanumeric DataView Column

My DataGridView's DataSource is bound to a DataView. The DataView is equal to my dtBills DataTable. Like so:
Dim View As New DataView
View.Table = DataSet1.Tables("dtBills")
dgvBills.DataSource = View
I have multiple columns in this DataGridView. One in particular has strings and integers as information. When I click on the DataGridView Column Header to sort the column, it sorts as strings like the column on the left:
'Curr Col >>> ' Wanted Result
10001 >>> 10001
100012 >>> 11000
11000 >>> 12000
110049 >>> 100012
12000 >>> 110049
E-1234 >>> E-1234
T-12345 >>> T-1235
T-1235 >>> T-12345
How would I go about sorting a bound DataGridView Column when pressing on the Column Header as I normally would? Should I use my DataView to help me out?
When a DataGridView is databound it is not possible to use its sorting and it is necessary to sort source data. The sorting is a bit complicated so I need two helper columns.
dgvBills.AutoGenerateColumns = False
tbl.Columns.Add(New DataColumn("Scol1", GetType(String)))
tbl.Columns.Add(New DataColumn("Scol2", GetType(Integer)))
The first one will contain a leading letters (or empty string). The second will contain only a number contained in the string. We will sort by Scol1, Scol2.
Now we set all comumns to Programatic mode (DataGridViewColumnSortMode Enumeration)
For Each column As DataGridViewColumn In dgvBills.Columns
column.SortMode = DataGridViewColumnSortMode.Programmatic
Next
And custom sorting is achieved in a handler of ColumnHeaderMouseClick (DataGridView.Sort Method (IComparer)). We will use sorting of the underlying view instead of the Grid sorting.
Private Sub dgvBills_ColumnHeaderMouseClick(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles dgvBills.ColumnHeaderMouseClick
Dim newColumn As DataGridViewColumn = dgvBills.Columns(e.ColumnIndex)
Dim direction As ListSortDirection
Dim Modifier As String = ""
If newColumn.HeaderCell.SortGlyphDirection = SortOrder.Ascending Then
direction = ListSortDirection.Descending
Modifier = " desc"
Else
direction = ListSortDirection.Ascending
End If
Dim View As DataView = dgvBills.DataSource
If {"JobNumber", "JobNumber1"}.Contains(dgvBills.Columns(e.ColumnIndex).Name) Then
View.Table.Columns("Scol2").Expression = String.Format("Convert(iif (substring({0},1,2) like '*-',substring({0},3,len({0})-1),{0}), 'System.Int32')", dgvBills.Columns(e.ColumnIndex).Name)
View.Table.Columns("Scol1").Expression = String.Format("iif (substring({0},1,2) like '*-',substring({0},1,2),'')", dgvBills.Columns(e.ColumnIndex).Name)
View.Sort = String.Format("Scol1 {0},Scol2 {0}", Modifier)
Else
dgvBills.Sort(newColumn, direction)
End If
If direction = ListSortDirection.Ascending Then
newColumn.HeaderCell.SortGlyphDirection = SortOrder.Ascending
Else
newColumn.HeaderCell.SortGlyphDirection = SortOrder.Descending
End If
End Sub
In {"JobNumber", "JobNumber1"}.Contains ... is possible to set columns which are sorted differntly. Other columns are sorted as the Grid sorts them by default or it is possible to create another custom sorting.
Note: I have fully working example but I hope that fragments are good enough.
The column is sorted correctly as strings and I suppose you want to sort it as numbers. The problem is that it seems that the strings you have combine numbers and characters. The result is necessity rather complex sorting for a DataView.
Dim tbl As New DataTable("dtBills")
Dim DataSet1 As New DataSet
DataSet1.Tables.Add(tbl)
tbl.Columns.Add(New DataColumn("MyCol", GetType(String)))
Dim vals As String() = {"10001", "100012", "11000", "110049", "12000", "E-1234", "T-12345", "T-1235"}
For qq = 0 To vals.Length - 1
Dim row As DataRow
row = tbl.NewRow
row(0) = vals(qq)
tbl.Rows.Add(vals(qq))
Next
tbl = DataSet1.Tables("dtBills")
tbl.Columns.Add(New DataColumn("Scol2", GetType(Integer)) With {.Expression = "Convert(iif (substring(MyCol,1,2) like '*-',substring(MyCol,3,len(MyCol)-1),MyCol), 'System.Int32')"})
tbl.Columns.Add(New DataColumn("Scol1", GetType(String)) With {.Expression = "iif (substring(MyCol,1,2) like '*-',substring(MyCol,1,2),'')"})
Dim View As New DataView(tbl)
View.Sort = "Scol1,Scol2"
View.Table = DataSet1.Tables("dtBills")
So two new columns are added. The first maintain sorting by initial letters the second to enable sorting by the number contained in the a string.

Adding two column values to listbox in vb.net

I have a table named users which has the following columns in it
User_id,user_name,user_pwd,First_Name,Middle_Name,Last_Name and user_type.
I have dataset named dst and created a table called user in the dataset. Now I want to populate listbox with user_Name, First_Name, Last_name of each and every row in the table user.
I am able to add one column value at a time but not getting how to add multiple column values of each row to listbox
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(row("User_Name"))
Next
Above code works perfectly but I also want to add First_name as well as last_name to the list box at the same time.
Use same approach as you have, but put all values you want in one string.
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
Dim sItemTemp as String
sItemTemp = String.Format("{0},{1},{2}", row("User_Name"), row("First_Name"), row("Last_Name"))
lstUsers.Items.Add(sItemTemp)
Next
String.Format() function will call .ToString() on all parameters.
In this case if row(ColumnName) is NULL value then .ToString() return just empty string
You have 2 choices:
Using the ListBox:
To use the ListBox, set the font to one that is fixed width like courier new (so that the columns line up), and add the items like this:
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(RPAD(row("User_Name"),16) & RPAD(row("First_Name"),16) & RPAD(row("Last_Name"),16))
Next
The RPAD function is defined like this:
Function RPAD(a As Object, LENGTH As Object) As String
Dim X As Object
X = Len(a)
If (X >= LENGTH) Then
RPAD = a : Exit Function
End If
RPAD = a & Space(LENGTH - X)
End Function
Adjust the LENGTH argument as desired in your case. Add one more for at least one space. This solution is less than ideal because you have to hard-code the column widths.
Use a DataGridView control instead of a ListBox. This is really the best option, and if you need, you can even have it behave like a ListBox by setting the option to select the full row and setting CellBorderStyle to SingleHorizontal. Define the columns in the designer, but no need to set the widths - the columns can auto-size, and I set that option in the code below. if you still prefer to set the widths, comment out the AutoSizeColumnsMode line.
The code to set up the grid and add the rows goes like this:
g.Rows.Clear() ' some of the below options are also cleared, so we set them again
g.AutoSizeColumnsMode = DataGridViewAutoSizeColumnMode.AllCells
g.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal
g.SelectionMode = DataGridViewSelectionMode.FullRowSelect
g.AllowUserToAddRows = False
g.AllowUserToDeleteRows = False
g.AllowUserToOrderColumns = True
For Each row As DataRow In dt.Rows
g.Rows.Add(row("User_Name"), row("First_Name"), row("Last_Name"))
Next
You might solved your problem by now but other users like me might have issue with it.
Above answers given worked for me even but I found a same answer in a simple way according to what I want..
cmd = New SqlCommand("select User_Name, First_Name, Last_Name from User")
Dim dr As SqlDataReader = cmd.ExecuteReader(YourConnectionString)
If dr.HasRows Then
Do While dr.Read
lst.Items.Add(dr.Item(0).ToString & " " & dr.Item(1).ToString & " " & dr.Item(2).ToString)
Loop
End If
This worked for me, maybe wrong way but I found it simple :)
May I suggest you use a ListView control instead of Listbox?
If you make the switch, here's a sample subroutine you could use to fill it up with the data you said you want. Adapt it the way you like; there's much room for improvement but you get the general idea:
Public Sub FillUserListView(lstUsers As ListView, Dst As DataSet)
Dim columnsWanted As List(Of String) = New List(Of String)({"User_Name", "First_Name", "Last_Name"})
Dim dt As DataTable = Dst.Tables("user")
Dim columns As Integer = 0
Dim totalColumns = 0
Dim rows As Integer = dt.Rows.Count
'Set the column titles
For Each column As DataColumn In dt.Columns
If columnsWanted.Contains(column.ColumnName) Then
lstUsers.Columns.Add(column.ColumnName)
columns = columns + 1
End If
totalColumns = totalColumns + 1
Next
Dim rowObjects(columns - 1) As ListViewItem
Dim actualColumn As Integer = 0
'Load up the rows of actual data into the ListView
For row = 0 To rows - 1
For column = 0 To totalColumns - 1
If columnsWanted.Contains(dt.Columns(column).ColumnName) Then
If actualColumn = 0 Then
rowObjects(row) = New ListViewItem()
rowObjects(row).SubItems(actualColumn).Text = dt.Rows(row).Item(actualColumn)
Else
rowObjects(row).SubItems.Add(dt.Rows(row).Item(actualColumn))
End If
lstUsers.Columns.Item(actualColumn).Width = -2 'Set auto-width
actualColumn = actualColumn + 1
End If
Next
lstUsers.Items.Add(rowObjects(row))
Next
lstUsers.View = View.Details 'Causes each item to appear on a separate line arranged in columns
End Sub