- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Crash (Endless loop) on any iteract to non-First row of DataGridView
(this thread seems related to general programming but as soon as I suffer the issue in context of Inventor-relatad project I hope it is not too-much off-topic here)
In one of my Inventor-related projects I'd like to provide user with Windows Form containing controls of some options (CheckBoxes) organized with DataGridView.
Here is a very simplified (Paint-created) version of the desired form:
Pay attention there are some <empty> (not an option) cells.
The hard thing of this task - irregularity of the CheckBoxCell pattern (should be generated dynamically according to some business logic that is not an object of this thread).
Initially I thought I need to use Boolean type for Columns where CheckBoxes are to be placed but that seems to be the wrong way (AFAIK CheckBoxCell can't be converted to an <empty cell>, at least all my attempts to do so were unsuccessful, see commented).
Then I search Internet a bit and found a mention that opposite conversation (from TextBoxCell to CheckBoxCell is possible).
Using this knowledge I get some progress towards the desired.
Now I can convert <empty cell> to checkbox with following iLogic code (see the DataBindingComplete sub):
Option Explicit On
AddReference "System.Data"
AddReference "System.Xml"
Imports System.Data
Imports System.Windows.Forms
Class AAA
Friend WithEvents oDGV As New DataGridView
Dim sHeader1 As String = "Name"
Dim sHeader2 As String = "Option1"
Dim sHeader3 As String = "Option2"
Sub Main
Dim oDT As DataTable = New DataTable
oDT.Columns.Add(sHeader1, GetType(String))
oDT.Columns.Add(sHeader2, GetType(String)) ' GetType(Boolean))
oDT.Columns.Add(sHeader3, GetType(String)) ' GetType(Boolean))
Dim names = New List(Of String)
names.Add("A1")
names.Add("A2")
' Dim opt1vals = New List(Of String)
' opt1vals.Add(False)
' opt1vals.Add(True)
' Dim opt2vals = New List(Of String)
' opt2vals.Add(True)
' opt2vals.Add(False)
Dim i As Integer = 0
For Each name in Names
oDT.Rows.Add(oDT.Columns.Count)
oDT.Rows(i)(sHeader1) = name
' oDT.Rows(i)(sHeader2) = opt1vals(i)
' oDT.Rows(i)(sHeader3) = opt2vals(i)
i +=1
Next
Dim oDV As DataView = oDT.DefaultView
With oDGV
.AllowUserToAddRows = False
.AutoSize = True
.DataSource = oDV
End With
Dim oForm As New Form
With oForm
.AutoSize = True
.Controls.Add(oDGV)
End With
' logger.info("oDGV.Rows.Count #1 = " & oDGV.Rows.Count)
oForm.ShowDialog()
End Sub
Sub oDGV_DataBindingComplete(ByVal sender As Object, ByVal E As DataGridViewBindingCompleteEventArgs) Handles oDGV.DataBindingComplete
logger.info("oDGV.Rows.Count #2 = " & oDGV.Rows.Count)
oDGV.Rows(0).Cells(sHeader3).Value = True
oDGV.Rows(0).Cells(sHeader3) = New DataGridViewCheckBoxCell()
' oDGV.Rows(1).Cells(sHeader2).Value = True ' !!! ENDLESS-LOOP
' oDGV.Rows(1).Cells(sHeader2) = New DataGridViewCheckBoxCell()
End Sub
' Sub oDGV_DataBindingComplete(ByVal sender As Object, ByVal E As DataGridViewBindingCompleteEventArgs) Handles oDGV.DataBindingComplete
' logger.info("oDGV.Rows.Count-2 = " & oDGV.Rows.Count)
' oDGV.Rows(0).Cells(sHeader2).Value = False
' oDGV.Rows(0).Cells(sHeader2) = New DataGridViewTextBoxCell()
' oDGV.Rows(0).Cells(sHeader2).Value = ""
' End Sub
End Class
BUT for some reason this behaves as expected ONLY for cells of the first row (row index = 0).
As soon as I try to do this for a cell in the second row (row index = 1) the code crashes (after some time of endless cycling ... which I detect by means of iLogic Log panel).
But the problem seems not the conversation itself ... the code goes to endless cycle even if I comment-out those two lines related to the second row but try to interact with any cell of second row!
What I'm missing?
Please vote for Inventor-Idea Text Search within Option Names
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
I've managed to get a bit closer to what I want with approach of disabling existing checkbox with the code based on CellPainting Event handle:
Option Explicit On
AddReference "System.Data"
AddReference "System.Drawing"
AddReference "System.Xml"
Imports System.Data
Imports System.Drawing
Imports System.Windows.Forms
Class AAA
Friend WithEvents oDGV As New DataGridView
Dim sHeader1 As String = "Name"
Dim sHeader2 As String = "Option1"
Dim sHeader3 As String = "Option2"
Sub Main
Dim oDT As DataTable = New DataTable
oDT.Columns.Add(sHeader1, GetType(String))
oDT.Columns.Add(sHeader2, GetType(Boolean))
oDT.Columns.Add(sHeader3, GetType(Boolean))
Dim names = New List(Of String)
names.Add("A1")
names.Add("A2")
Dim opt1vals = New List(Of String)
opt1vals.Add(False)
opt1vals.Add(True)
Dim opt2vals = New List(Of String)
opt2vals.Add(True)
opt2vals.Add(False)
Dim i As Integer = 0
For Each name in Names
oDT.Rows.Add(oDT.Columns.Count)
oDT.Rows(i)(sHeader1) = name
oDT.Rows(i)(sHeader2) = opt1vals(i)
oDT.Rows(i)(sHeader3) = opt2vals(i)
i +=1
Next
Dim oDV As DataView = oDT.DefaultView
With oDGV
.AllowUserToAddRows = False
.AutoSize = True
.DataSource = oDV
End With
Dim oForm As New Form
With oForm
.AutoSize = True
.Controls.Add(oDGV)
End With
oForm.ShowDialog()
End Sub
Sub oDGV_CellPainting(ByVal sender As Object, ByVal e As DataGridViewCellPaintingEventArgs) Handles oDGV.CellPainting
logger.info(1)
' If e.RowIndex = 0 And e.ColumnIndex = 1 ' sHeader2
' Dim cell1 As DataGridViewCell = oDGV.Rows(0).Cells(sHeader2)
' Dim chkCell1 As DataGridViewCheckBoxCell = TryCast(cell1, DataGridViewCheckBoxCell)
' chkCell1.Value = False
' chkCell1.FlatStyle = FlatStyle.Flat
' chkCell1.Style.ForeColor = Color.DarkGray
' cell1.ReadOnly = True
' End If
If e.RowIndex = 1 And e.ColumnIndex = 2
Dim cell2 As DataGridViewCell = oDGV.Rows(1).Cells(sHeader3)
Dim chkCell2 As DataGridViewCheckBoxCell = TryCast(cell2, DataGridViewCheckBoxCell)
chkCell2.Value = False
chkCell2.FlatStyle = FlatStyle.Flat
chkCell2.Style.ForeColor = Color.DarkGray
cell2.ReadOnly = True
End If
End Sub
End Class
Now I can clear disable checkboxes not only in the first row.
But I still worry about the fact that the sub is called 24 times for single cell and get to endless cycle (at least without crashing) if un-comment the code lines related to the checkbox in a first row ...
... I believe it will crash on real check box chart with dozens checkboxes.
Any ideas?
Please vote for Inventor-Idea Text Search within Option Names
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Ok endless loop seems to be triggered with cell value line(s):
chkCell1.Value = True
Event Handler Sub shouldn't contain lines changing cells' values.
I still don't understand why the sub is triggered so many times yet now I got more-or-less what I need without endless cycle.
PS:
I'll keep the thread open for some time in case somebody want to share a better solution.
Please vote for Inventor-Idea Text Search within Option Names
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
The form I'm working on will have much more options than names thus I decided to optimize it a bit - swap rows with columns (AFAIK such table transformation is called "Pivot") but got to some re-paint issue that I don't understand how to overcome.
My current code is:
Option Explicit On
AddReference "System.Data"
AddReference "System.Drawing"
AddReference "System.Xml"
Imports System.Data
Imports System.Drawing
Imports System.Windows.Forms
Class UserSetsForm
Friend WithEvents oDGV As New DataGridView
Dim sHeader1 As String = " "
Dim sHeaderIPT As String = "*.ipt"
Dim sHeaderIAM As String = "*.iam"
Dim sHeaderIDW As String = "*.idw"
Sub Main
Dim optNames = New List(Of String)
optNames.AddRange({"00-AAA", "2D-AAA", "3D-AAA", "00-ABC", "2D-ABC", "3D-ABC"})
Dim oDT As DataTable = dataTableVERT(optNames)
' Dim oDT As DataTable = dataTableHOR(optNames)
Dim oDV As DataView = oDT.DefaultView
With oDGV
.AllowUserToAddRows = False
.AutoSize = True
.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
.BackgroundColor = Drawing.Color.White
.DataSource = oDV
End With
Dim oForm As New Form
With oForm
.AutoSize = True
.Controls.Add(oDGV)
End With
oForm.ShowDialog()
End Sub
Function dataTableVERT(optNames As List(Of String)) As dataTable
Dim oDT_V As DataTable = New DataTable
oDT_V.Columns.Add(sHeader1, GetType(String))
oDT_V.Columns.Add(sHeaderIPT, GetType(Boolean))
oDT_V.Columns.Add(sHeaderIAM, GetType(Boolean))
oDT_V.Columns.Add(sHeaderIDW, GetType(Boolean))
Dim i As Integer = 0
For Each cn in optNames
oDT_V.Rows.Add(oDT_V.Columns.Count)
oDT_V.Rows(i)(sHeader1) = cn
i +=1
Next
Return oDT_V
End Function
Function dataTableHOR(optNames As List(Of String)) As dataTable
Dim oDT_H As DataTable = New DataTable
oDT_H.Columns.Add(sHeader1, GetType(String))
For Each cn in optNames
oDT_H.Columns.Add(cn, GetType(Boolean))
Next
oDT_H.Rows.Add(oDT_H.Columns.Count)
oDT_H.Rows(0)(sHeader1) = sHeaderIPT
oDT_H.Rows.Add(oDT_H.Columns.Count)
oDT_H.Rows(1)(sHeader1) = sHeaderIAM
oDT_H.Rows.Add(oDT_H.Columns.Count)
oDT_H.Rows(2)(sHeader1) = sHeaderIDW
Return oDT_H
End Function
Sub ChkBoxDisable(cell As DataGridViewCell)
Dim chkCell As DataGridViewCheckBoxCell = TryCast(cell, DataGridViewCheckBoxCell)
chkCell.FlatStyle = FlatStyle.Flat
chkCell.Style.ForeColor = Color.DarkGray
cell.ReadOnly = True
End Sub
Sub oDGV_CellPainting(ByVal sender As Object, ByVal e As DataGridViewCellPaintingEventArgs) Handles oDGV.CellPainting
''' Disable choosing non-applicable check-boxes
If e.RowIndex >= 0 And e.ColumnIndex >= 1
Dim row As DataGridViewRow = oDGV.Rows(e.RowIndex)
Dim column As DataGridViewColumn = oDGV.Columns(e.ColumnIndex)
Select Case True
''' CASES-for-VERTICAL-table
Case row.Cells(sHeader1).Value.StartsWith("2D-") And (column.HeaderText = sHeaderIPT OR column.HeaderText = sHeaderIAM)
ChkBoxDisable(oDGV.Rows(e.RowIndex).Cells(sHeaderIAM))
ChkBoxDisable(oDGV.Rows(e.RowIndex).Cells(sHeaderIPT))
Case row.Cells(sHeader1).Value.StartsWith("3D-") And (column.HeaderText = sHeaderIDW)
ChkBoxDisable(oDGV.Rows(e.RowIndex).Cells(sHeaderIDW))
''' CASES-for-HORIOZONTAL-table (??? poor-painting ???)
Case column.HeaderText.StartsWith("2D-") AndAlso (row.Cells(sHeader1).Value = sHeaderIPT OR row.Cells(sHeader1).Value = sHeaderIAM)
ChkBoxDisable(oDGV.Rows(sHeaderIPT).Cells(e.ColumnIndex))
ChkBoxDisable(oDGV.Rows(sHeaderIAM).Cells(e.ColumnIndex))
Case column.HeaderText.StartsWith("3D-") AndAlso row.Cells(sHeader1).Value = sHeaderIDW
ChkBoxDisable(oDGV.Rows(sHeaderIDW).Cells(e.ColumnIndex))
End Select
End If
End Sub
End Class
If DataTable is created as Vertical (line 26) then I get 100% OK result:
But if DataTable is created Horizontal/"Pivoted" (line 27) then most cells got stuck until hovered with mouse pointer (but even re-drawed with pointer the disabled checkboxes are not shown):
PS:
Dear @MjDeck I'm very sorry for disturbing you but, I understand that this thread is not Inventor-related but kindly hope you can look into and comment on this.
Please vote for Inventor-Idea Text Search within Option Names
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi Maxim - the CellPainting event is not a good place to do this. That's more suited for customizing the appearance of the cell.
Here's a new version of your rule. This sets the read-only state with the same logic that you were using in oDgv_CellPainting. But it does it in the Form.Shown event. The system will call that only once, and it will call it after the DataGridView has been populated. So that's a good time to set some cells to read-only.
I also made a small change to the Rows.Add() lines. You were calling them with the columns count as an argument. I think that value is ignored, so I took it out just to make the code more clear. Let me know if I missed something here.

Mike Deck
Software Developer
Autodesk, Inc.