Sorting DataTable Column Using DataGridView - vb.net

I'm trying to sort a DataTable that contains some dates and values. I pass the DataTable information to a DataGridView and sort the data, then try to pass it back.
The below code runs successfully, but does not produce any difference:
Form1.DataGridView1.DataSource = ChartTable
Form1.DataGridView1.Sort(Form1.DataGridView1.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
ChartTable = CType(Form1.DataGridView1.DataSource, DataTable).Copy()
ChartTable = ChartTable.DefaultView.ToTable
For i = 0 To ChartTable.Rows.Count - 1
Debug.Print("ChartTable = " & ChartTable.Rows(i)(0) & ", DataGrid = " & Form1.DataGridView1.Rows(i).Cells(0).Value)
Next
Here's the Output from the Debug.Print
ChartTable = 30/12/15, DataGrid = 27/10/15
ChartTable = 27/10/15, DataGrid = 19/11/15
ChartTable = 29/12/15, DataGrid = 22/12/15
ChartTable = 22/12/15, DataGrid = 29/12/15
ChartTable = 19/11/15, DataGrid = 30/12/15
The ChartTable (which is the DataTable) is still in it's original un-sorted state.
Am I missing something?

I think that it's because Datagridview sorts the data for himself, not doing changes to his datasource. When you copy the datasource, are copying the non-sorted datatable.
To do what you want, i think you may have to do a process to get row by row of the datagridview to the datatable.
But, in my opinion, it should be a lot better (and faster) if you sort the info before to fill the datatable.

You can use this code to sort your data table:
Dim filterExp As String = ""
Dim sortExp As String = dt.Columns.Item(0).ColumnName
Dim i As Integer
Dim dtrow() As DataRow
dtrow = dt.Select(filterExp, sortExp, DataViewRowState.CurrentRows)
For i = 0 To dtrow.Length - 1
DataGridView1.Rows.Add(dtrow(i)(dt.Columns.Item(0).ColumnName))
Next

Related

Using one DataTable as the source in multiple UserControls in WinForms

I have created a local DataTable in my DataSet. I then have two User Controls with Data Grids on them.
I am trying to add data to the Data Table from UserControl1 and then be able to view this data in the UserControl2.
The Current structure is - DataSet - DataTableClients
DataGrids on both user controls have DataSource property set to 'DataTableClientsBindingSource" from the DataSet.
Adding clients works fine as I can see DataGrid rows populating in the UserControl1:
Dim clientsDT As DataTable = DataSet.DataTableClients
Dim row As DataRow
Dim i As Integer
For i = 1 To iClientNo
row = clientsDT.NewRow()
row("ClientNo") = Controls("LblClient" & i.ToString()).Text
row("Title") = Controls("CboTitle" & i.ToString()).Text
row("FirstName") = Controls("TxtFName" & i.ToString()).Text
row("Surname") = Controls("TxtSurname" & i.ToString()).Text
row("ReportName") = Controls("TxtFName" & i.ToString()).Text.Substring(0, 1) & " " & Controls("TxtSurname" & i.ToString()).Text
clientsDT.Rows.Add(row)
Next
However, when I switch to my UserControl2, the DataGrid on that control is empty, even though the DataSource is set and pointing to the same DataTable.
Help would be appreciated.

Capturing an event such as mouse click in Datagridview in VB

Update 5/21/17. Thank you for the suggestion of using a Table. That was helpful. I actually figured it out. I made myinputable a global variable by declaring the Dim statement at the top and making it a Datagridview type. Now I can turn it off in the other event that I needed to do it.
I am a novice. I have created a Datagridview in VB 2015 to capture a bunch of data from the use. When the user is finished with the data entry, I want to store the cell values in my variables. I do not know how to capture any event from my dynamically created datagridview "myinputable." My code is below. Please help.
Private Sub inputmodel()
Dim prompt As String
Dim k As Integer
'
' first get the problem title and the number of objectives and alternatives
'
prompt = "Enter problem title: "
title = InputBox(prompt)
prompt = "Enter number of criteria: "
nobj = InputBox(prompt)
prompt = "Enter number of alternatives: "
nalt = InputBox(prompt)
'
' now create the table
'
Dim Myinputable As New DataGridView
Dim combocol As New DataGridViewComboBoxColumn
combocol.Items.AddRange("Increasing", "Decreaing", "Threashold")
For k = 1 To 6
If k <> 2 Then
Dim nc As New DataGridViewTextBoxColumn
nc.Name = ""
Myinputable.Columns.Add(nc)
Else
Myinputable.Columns.AddRange(combocol)
End If
Next k
' now add the rows and place the spreadsheet on the form
Myinputable.Rows.Add(nobj - 1)
Myinputable.Location = New Point(25, 50)
Myinputable.AutoSize = True
Me.Controls.Add(Myinputable)
FlowLayoutPanel1.Visible = True
Myinputable.Columns(0).Name = "Name"
Myinputable.Columns(0).HeaderText = "Name"
Myinputable.Columns(1).Name = "Type"
Myinputable.Columns(1).HeaderText = "Type"
Myinputable.Columns(2).Name = "LThresh"
Myinputable.Columns(2).HeaderText = "Lower Threshold"
'Myinputable.Columns(2).ValueType = co
Myinputable.Columns(3).Name = "UThresh"
Myinputable.Columns(3).HeaderText = "Upper Threshold"
Myinputable.Columns(4).Name = "ABMin"
Myinputable.Columns(4).HeaderText = "Abs. Minimum"
Myinputable.Columns(5).Name = "ABMax"
Myinputable.Columns(5).HeaderText = "Abs. Maximum "
Myinputable.Rows(0).Cells(0).Value = "Help"
If Myinputable.Capture = True Then
MsgBox(" damn ")
End If
End Sub
As #Plutonix suggests, you should start by creating a DataTable. Add columns of the appropriate types to the DataTable and then bind it to the grid, i.e. assign it to the DataSource of your grid, e.g.
Dim table As New DataTable
With table.Columns
.Add("ID", GetType(Integer))
.Add("Name", GetType(String))
End With
DataGridView1.DataSource = table
That will automatically add the appropriate columns to the grid if it doesn't already have any, or you can add the columns in the designer and set their DataPropertyName to tell them which DataColumn to bind to. As the user makes changes in the grid, the data will be automatically pushed to the underlying DataTable.
When you're done, you can access the data via the DataTable and even save the lot to a database with a single call to the Update method of a data adapter if you wish.

Add default Item to data bound ComboBox

I have a function that brings back a datatable [GetDrinks()]
I use the function to populate a data source.
I want add a default value 'Select Drink' but it doesn't seem to work as it only shows the values form the datagrid.
Any ideas to get around this?
cboDrinks.DataSource = GetDrinks()
cboDrinks.DisplayMember = "Drink_DESCN"
cboDrinks.ValueMember = "Drink_ID"
cboDrinks.Items.Insert(0, " Select Drink ")
cboDrinks.SelectedIndex = 0
Per my comment, you need to insert the data into the DataTable that you are getting from GetDrinks:
Dim dt As DataTable = GetDrinks()
Dim row as DataRow = dt.NewRow
row("Drink_ID") = 0
row("Drink_DESCN") = " Select Drink "
dt.Rows.InsertAt(row, 0)
cboDrinks.DisplayMember = "Drink_DESCN"
cboDrinks.ValueMember = "Drink_ID"
cboDrinks.DataSource = dt
cboDrinks.SelectedIndex = 0
Note: Set the DisplayMember and ValueMember before the DataSource to avoid multiple refresh calls to the control.

Make particular column as combo box of DataGridView

I just want to make Data Grid. Where first and second column of data grid is for storing single value and third column as combo box.
The code that i tried is
Dim productGrid As New DataGridView
ProductGrid.Columns(0).Name = "CB"
ProductGrid.Columns(1).Name = "ProductGroup"
ProductGrid.Columns(2).Name = "Product"
Dim i As Integer
With ProductGrid
If .Rows.Count = 0 Then Exit Sub
i = 1
Dim objValueItems As New DataGridViewComboBoxCell
objValueItems.Items.Add("Server")
objValueItems.Items.Add("Standalone")
objValueItems.Items.Add("Demo")
objValueItems.Items.Add("Anywhere")
ProductGrid.Item(2, i).Value = objValueItems
End With
I am getting the error on "ProductGrid.Item(2, i).Value = objValueItems" this line. Error is " Index was out of range.
Bear in mind that all the cells of a ComboBox DGV Column have the same contents, thus you are not assigning a list of items to a given cell, but to all of them (to a column). You have to include this when adding the given column. Sample code:
Dim productGrid As New DataGridView
With productGrid
.Columns.Add("CB", "CB") 'Text-type column
.Columns.Add("ProductGroup", "ProductGroup") 'Text-type column
Dim objValueItems As New DataGridViewComboBoxColumn
With objValueItems
.Name = "Product"
.Items.Add("Server")
.Items.Add("Standalone")
.Items.Add("Demo")
.Items.Add("Anywhere")
End With
.Columns.Add(objValueItems) 'ComboBox-type column
End With

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