Re: After sorting DataGridView lose checks in CheckBox Column
What are the checkboxes there for? If they are row specific then you need to include them, if not in the database, at least in the relevant datatable in your program. If you add a Boolean column to the table after it is filled, you can use that to keep a record of checked and unchecked which will then be retained in the DGV sort.
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
Re: After sorting DataGridView lose checks in CheckBox Column
Thanks for the reply dunfiddlin.
The check box column will be used just to select individual rows, rather than selecting them with Ctrl/Shift.
I will then want to refer to the rows that are checked and grab information from them.
Which method do you think would be best for achieving this..?
Re: After sorting DataGridView lose checks in CheckBox Column
So what you're really asking for is a way to retain selections through a new sort which is whole different kettle of fish and not easily achieved (if indeed it's possible at all). Is there a particular reason for this because it's not immediately obvious why you would need this behaviour?
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
Re: After sorting DataGridView lose checks in CheckBox Column
The following similates loading data into a DataTable from a database then adds a column for allowing users to check the rows they want. A language extension is used to get the selected rows. Also there is code to keep the current row selected when you sort via the DataGridView column headers.
Requires a DataGridView and a Button. Note the one section of code must be in a code module and not a class or form.
For the code in Button1 the display goes to the IDE output window. Also note we are dealing with the data rather than the rows of the DataGridView.
Code module
Code:
<System.Diagnostics.DebuggerStepThrough()> _
<Runtime.CompilerServices.Extension()> _
Public Function GetChecked(ByVal sender As DataGridView, ByVal ColumnName As String) As List(Of DataGridViewRow)
Return (From Rows In sender.Rows.Cast(Of DataGridViewRow)() Where CBool(Rows.Cells(ColumnName).Value) = True).ToList
End Function
Form code
Code:
WithEvents bsData As New BindingSource
Private RowIdentifier As String = ""
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.AddRange(New DataColumn() _
{
New DataColumn("Identifier", GetType(System.String)),
New DataColumn("C1", GetType(System.String)),
New DataColumn("C2", GetType(System.String)),
New DataColumn("C3", GetType(System.Decimal)),
New DataColumn("C4", GetType(System.String))
}
)
dt.Rows.Add(New Object() {1, "A", "1", 3.0, "AAAA"})
dt.Rows.Add(New Object() {2, "B", "2", 10.5, "BBBB"})
dt.Rows.Add(New Object() {3, "C", "3", 4567.66, "CCCC"})
dt.Columns.Add(New DataColumn("Process", GetType(System.Boolean)))
dt.Columns("Process").SetOrdinal(0)
dt.Columns("Identifier").ColumnMapping = MappingType.Hidden
For Each row As DataRow In dt.Rows
row("Process") = False
Next
dt.AcceptChanges()
bsData.DataSource = dt
DataGridView1.DataSource = bsData
End Sub
Private Sub bsData_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles bsData.PositionChanged
RowIdentifier = CType(bsData.Current, DataRowView).Item("Identifier").ToString()
End Sub
Private Sub DataGridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.Sorted
bsData.Position = bsData.Find("Identifier", RowIdentifier)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Checked = CType(bsData.DataSource, DataTable).GetChecked("Process")
For Each row In Checked
Console.WriteLine(String.Join(",", row.ItemArray))
Next
End Sub
Re: After sorting DataGridView lose checks in CheckBox Column
dunfiddlin - Well once certain rows have been checked a user may want to then sort other columns to help find the information they was looking for. So it makes sense that the checks are retained during this process. Also in the future I may want the checked rows to automatically jump to the top, but not sure yet.
kevininstructor - thanks a lot for your reply and code sample. I made a new module and inserted your "Code Module" code. I then pasted all your "Form Code" in. I get an error in the button code:
vb Code:
Dim Checked = CType(bsData.DataSource, DataTable).GetChecked("Process")
It says 'GetChecked is not a member of 'System.Data.DataTable'.
I know you said this "For the code in Button1 the display goes to the IDE output window"
I'm not really sure what that means, or if I need to do something else..?
Re: After sorting DataGridView lose checks in CheckBox Column
Originally Posted by squatman
kevininstructor - thanks a lot for your reply and code sample. I made a new module and inserted your "Code Module" code. I then pasted all your "Form Code" in. I get an error in the button code:
vb Code:
Dim Checked = CType(bsData.DataSource, DataTable).GetChecked("Process")
It says 'GetChecked is not a member of 'System.Data.DataTable'.
I know you said this "For the code in Button1 the display goes to the IDE output window"
I'm not really sure what that means, or if I need to do something else..?
Thanks again, it is much appreciated.
I gave you the wrong extension, had one for DataGridView, one for DataTable. Any ways I tweaked the one missing and placed it into a demo VS2010 project attached below. Note how I show the data in a child form via a DataTable rather than a List(Of DataRow) via LINQ/Language extension.
If tvw_CurrentProjects.SelectedNode.Level = 0 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
Me.dgv_DocumentListCP.DataSource = dv
ElseIf tvw_CurrentProjects.SelectedNode.Level = 1 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
Me.dgv_DocumentListCP.DataSource = dv
ElseIf tvw_CurrentProjects.SelectedNode.Level = 2 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
Me.dgv_DocumentListCP.DataSource = dv
ElseIf tvw_CurrentProjects.SelectedNode.Level = 3 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "' AND [Document Type 2 = DC Level 7]='" & DocType2 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
Me.dgv_DocumentListCP.DataSource = dv
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Something Went Wrong", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
cn.Close()
cn.Dispose()
dgv_DocumentListCP.ClearSelection()
PrepareColumns()
I tried this:
vb Code:
Dim DA As New OleDbDataAdapter
Dim DS As New DataSet
Dim cn As OleDbConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DatabaseLocation & "Job_" & DocumentListCP_ProjectID_Local & ".accdb;")
cn.Open()
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM Documents WHERE `Lock` = 'off'", cn)
If tvw_CurrentProjects.SelectedNode.Level = 0 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
bsData.DataSource = dv
Me.dgv_DocumentListCP.DataSource = bsData
ElseIf tvw_CurrentProjects.SelectedNode.Level = 1 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
bsData.DataSource = dv
Me.dgv_DocumentListCP.DataSource = bsData
ElseIf tvw_CurrentProjects.SelectedNode.Level = 2 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
bsData.DataSource = dv
Me.dgv_DocumentListCP.DataSource = bsData
ElseIf tvw_CurrentProjects.SelectedNode.Level = 3 Then
Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "' AND [Document Type 2 = DC Level 7]='" & DocType2 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
bsData.DataSource = dv
Me.dgv_DocumentListCP.DataSource = bsData
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Something Went Wrong", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
cn.Close()
cn.Dispose()
dgv_DocumentListCP.ClearSelection()
PrepareColumns()
But the Catch ex As Exception caught the error...
Is there a simple way to implement it into my code..?
Re: After sorting DataGridView lose checks in CheckBox Column
You could load all data as I suggested in regards to the BindingSource then filter via the BindingSource. The example below is altered from my first example, this one loads data from Customers.xml which was extracted from NorthWnd.mdb from Microsoft. Note how the filter code works, in a sense mimics what you are doing for the DataView code. If this does not make sense let me know. I will be away from my computer for about two hours.
Code:
Public Class Form1
WithEvents bsData As New BindingSource
Private RowIdentifier As String = ""
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ds As New DataSet
ds.ReadXml("Customers.xml")
Dim dt = ds.Tables(0)
dt.Columns.Add(New DataColumn("Process", GetType(System.Boolean)))
dt.Columns("CustomerID").ColumnMapping = MappingType.Hidden
dt.Columns("Process").SetOrdinal(0)
For Each row As DataRow In dt.Rows
row("Process") = False
Next
dt.AcceptChanges()
bsData.DataSource = dt
DataGridView1.DataSource = bsData
End Sub
Private Sub bsData_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles bsData.PositionChanged
If bsData.Current IsNot Nothing Then
RowIdentifier = CType(bsData.Current, DataRowView).Item("CustomerID").ToString()
End If
End Sub
Private Sub DataGridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.Sorted
bsData.Position = bsData.Find("CustomerID", RowIdentifier)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGetCheckedRows.Click
Dim f As New Form2
Try
f.DataGridView1.DataSource = CType(bsData.DataSource, DataTable).GetChecked("Process")
f.ShowDialog()
Finally
f.Dispose()
End Try
End Sub
Private Sub cmdFilter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdFilter.Click
bsData.Filter = "Country = 'Germany' AND City = 'Berlin'"
End Sub
Private Sub cmdRemoveFilter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRemoveFilter.Click
bsData.Filter = ""
End Sub
End Class
'ElseIf tvw_CurrentProjects.SelectedNode.Level = 1 Then
' Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
' Me.dgv_DocumentListCP.DataSource = dv
'ElseIf tvw_CurrentProjects.SelectedNode.Level = 2 Then
' Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
' Me.dgv_DocumentListCP.DataSource = dv
'ElseIf tvw_CurrentProjects.SelectedNode.Level = 3 Then
' Dim dv As New DataView(dt, "[Category = DC Level 4]='" & DocumentListCP_Category_Local & "' AND [Discipline = DC Level 5]='" & Discipline & "' AND [Document Type 1 = DC Level 6]='" & DocType1 & "' AND [Document Type 2 = DC Level 7]='" & DocType2 & "'", "[Doc No Int] ASC", DataViewRowState.CurrentRows)
' Me.dgv_DocumentListCP.DataSource = dv
'End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Something Went Wrong", MessageBoxButtons.OK, MessageBoxIcon.Error)
MessageBox.Show(ex.Message, "Something Went Wrong1", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
I get the message pop up "Object reference not set to an instance of an object." I click ok, then my DGV is populated and the CheckBox column is there and appears to be working...
Re: After sorting DataGridView lose checks in CheckBox Column
In the last reply you create a DataColumn named CheckBox then from what I see change ColumnMappings for a column named CheckBoxMap, does that column exists or did you mean CheckBox rather than CheckBoxMap?
Re: After sorting DataGridView lose checks in CheckBox Column
Error 1 (is responsible for error 2)
The error is because each row the Boolean column (using code from my example) for/each loop did not complete, if it had then you would not get the Null error
Code:
For Each row As DataRow In dt.Rows
row("Process") = False
Next
Error 2
The other error pointing to CheckBoxMap is from reading your code does not exists (also see my last reply which addresses this).
Re: After sorting DataGridView lose checks in CheckBox Column
Kevin you god!
Where you was using "dt.Columns("CustomerID").ColumnMapping = MappingType.Hidden" I got mixed up, I didn't actually need this. So my previous second error I changed "CheckBoxMap" to a column "ID" that I already have from my database. Now all appears to be working
Only problem now is, I check 4 rows, transfer then to another DGV iy only bring across 3 of them, unless I move the row selection to a different one. It's as if it's not registering the last "Check". Any ideas..?
Thanks again kevin, I have no idea how you knew how to come up with that code and create your own awesome functions. I'd be very interested in some VB.net book recommendations. I know there are tonnes of resources, but it's just nice sometime to sit down with a book. So if you have any recommendations, maybe even some that you've used please let me know.
Re: After sorting DataGridView lose checks in CheckBox Column
In regards to checking four rows and only three coming across, this might have something to do with how the data is loaded via the DataAdapter. Try the following
Code:
Private Sub DataGridView1_CurrentCellDirtyStateChanged(
ByVal sender As Object,
ByVal e As EventArgs) _
Handles DataGridView1.CurrentCellDirtyStateChanged
If TypeOf DataGridView1.CurrentCell Is DataGridViewCheckBoxCell Then
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End Sub
In regards to the code I presented, I have been coding for years and over time have created a) a repository b) a library of code for questions for online forums or for work. What is critical is developing code such as this way before you need it since when you need it there is less time generally to learn as you go especially with my position that when something breaks millions of people are affected. With that kind of pressure there is no time to learn as you go.
Concerning books, have not read anything for .NET but do read MSDN online standard documentation which many times will give you answers or if not using information there can assist searching via Google to get more information that always one to get what they need.