Crash (Endless loop) on any iteract to non-First row of DataGridView

Crash (Endless loop) on any iteract to non-First row of DataGridView

Maxim-CADman77
Advisor Advisor
477 Views
4 Replies
Message 1 of 5

Crash (Endless loop) on any iteract to non-First row of DataGridView

Maxim-CADman77
Advisor
Advisor

(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:

Tabled-Options-Form.png

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

0 Likes
478 Views
4 Replies
Replies (4)
Message 2 of 5

Maxim-CADman77
Advisor
Advisor

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.

CheckBox-Chart-with-Disabled-Instances.png

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

0 Likes
Message 3 of 5

Maxim-CADman77
Advisor
Advisor

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

0 Likes
Message 4 of 5

Maxim-CADman77
Advisor
Advisor

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:

Vert-Table-OK.png

 

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):

Hor-Table-Cell-Pint-FAILURE.png

 

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

0 Likes
Message 5 of 5

MjDeck
Autodesk
Autodesk

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.