Я использую VS2008, и мне удалось собрать воедино код, которому я себя научил (плохо), вместе с тем, что я нашел в Интернете, и теперь я врезался в стену. Я осмотрелся вокруг и не могу понять, как обойти эту проблему.
Когда кто-то нажимает кнопку, которую я распределяю между двумя модулями, первый помещает графическую рамку поверх сетки данных и раскручивает изображение, ожидая, пока второй поток сохранит данные в Excel. Проблема, которую я получаю, - это сообщение об ошибке «объект используется где-то еще», когда он попадает в строку «Me.PictureBox4.Image = DirectCast (BM_out.Clone (), System.Drawing.Image)» во время выполнения кода.
Public MoveByCalc As Double
Public ReturnStack As New System.Collections.Generic.Stack(Of Integer)
Public BM_In As New Bitmap(My.Resources.Fan)
Public Wid As Single = BM_In.Width
Public Hgt As Single = BM_In.Height
Public Cx As Single = Wid / 2
Public Cy As Single = Hgt / 2
Public TimeElapsed As Single = 1
Public EndThread As String = "No"
Public X As Integer
Public BS As New BindingSource
Public AutoNum As Integer
Public CellConnection As New OleDbConnection
Public DB1Connection As New OleDbConnection
Public DB2Connection As New OleDbConnection
Public OldScrollValue As Integer : Public Direction As Integer
Public objDataAdapter As New OleDbDataAdapter()
Public objDataSet As New DataSet()
Public objDataAdapterDB1 As New OleDbDataAdapter()
Public objDataSetDB1 As New DataSet()
Public objDataAdapterDB2 As New OleDbDataAdapter()
Public objDataSetDB2 As New DataSet()
Public DBCount As String
Public LoadError As Integer
Public TempString As String
Public DisableSearch As Integer
Public DataGridTop As Double
Public DataGridHeight As Double
Public DataGridBottom As Double
Public DBLoc As Integer
Public ButtonSelectedColour As Color = Color.FromArgb(253, 183, 89)
Public Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CloseButton.Click
PictureBox4.Visible = True
PictureBox4.Top = DataGridView1.Top : PictureBox4.Left = DataGridView1.Left
PictureBox4.Height = DataGridView1.Height : PictureBox4.Width = DataGridView1.Width
EndThread = "No"
DataGridView1.DataSource = objDataSet.Tables(0).DefaultView
Dim T As Thread
T = New Thread(AddressOf Me.FanSpin)
T.Start()
Dim S As Thread
S = New Thread(AddressOf Me.SaveData)
S.Start()
End Sub
Private Sub FanSpin()
Dim KeepRunning As Boolean = True
'On Error GoTo EndThread
While KeepRunning
TimeElapsed = TimeElapsed + 1
Dim Corners As Point() = { _
New Point(0, 0), _
New Point(Wid, 0), _
New Point(0, Hgt), _
New Point(Wid, Hgt)}
Dim I As Long
For I = 0 To 3
Corners(I).X -= Cx
Corners(I).Y -= Cy
Next I
Dim theta As Single = Single.Parse(-TimeElapsed) * PI / 180.0
Dim X As Single
Dim Y As Single
For I = 0 To 3
X = Corners(I).X
Y = Corners(I).Y
Corners(I).X = X * Cos(theta) + Y * Sin(theta)
Corners(I).Y = -X * Sin(theta) + Y * Cos(theta)
Next I
Dim xmin As Single = Corners(0).X
Dim ymin As Single = Corners(0).Y
For I = 1 To 3
If xmin > Corners(I).X Then xmin = Corners(I).X
If ymin > Corners(I).Y Then ymin = Corners(I).Y
Next I
For I = 0 To 3
Corners(I).X -= xmin
Corners(I).Y -= ymin
Next I
Dim BM_out As Bitmap = New Bitmap(CInt(-2 * xmin), CInt(-2 * ymin))
Dim gr_out As Graphics = Graphics.FromImage(BM_out)
ReDim Preserve Corners(2)
SyncLock BM_In
gr_out.DrawImage(BM_In, Corners)
End SyncLock
If BM_out IsNot Nothing Then
SyncLock BM_out
Me.PictureBox4.Image = DirectCast(BM_out.Clone(), System.Drawing.Image)
End SyncLock
End If
If EndThread = "Yes" Then
KeepRunning = False
End If
End While
EndThread:
PictureBox4.Image = Nothing
If Me.PictureBox4.InvokeRequired Then
PictureBox4.Invoke(New Action(AddressOf PictureBox4.Hide))
Else
Me.PictureBox4.Visible = False
End If
End Sub
Public Sub DataBindToDataGrid()
Select Case ReturnStack.Peek()
Case 1
DataGridView1.DataSource = objDataSetDB1.Tables(0).DefaultView
Case 2
DataGridView1.DataSource = objDataSetDB2.Tables(0).DefaultView
End Select
End Sub
Private Sub SaveData()
Dim CallDataBindToDataGrid As New MethodInvoker(AddressOf Me.DataBindToDataGrid)
Dim XLApp As New Excel.Application
Dim Wb As Excel.Workbook
Dim Ws As Excel.Worksheet
Dim XlRange As Excel.Range
XLApp = New Excel.Application
Wb = XLApp.Workbooks.Open(My.Settings.Database3C)
Ws = Wb.Worksheets("Data")
Ws.Activate()
Ws.Unprotect()
XlRange = Ws.Range("A5", "V100")
XlRange.ClearContents()
XlRange = Ws.Range("A5")
Dim Count As Integer = 0
For Count = 0 To 49
XlRange.Value = DataGridView1.Rows(Count).Cells(0).Value
XlRange.Offset(0, 1).Value = DataGridView1.Rows(Count).Cells(1).Value.ToString
XlRange.Offset(0, 2).Value = DataGridView1.Rows(Count).Cells(2).Value.ToString
XlRange.Offset(0, 3).Value = DataGridView1.Rows(Count).Cells(3).Value.ToString
XlRange.Offset(0, 4).Value = DataGridView1.Rows(Count).Cells(4).Value.ToString
XlRange.Offset(0, 5).Value = DataGridView1.Rows(Count).Cells(5).Value.ToString
XlRange.Offset(0, 6).Value = DataGridView1.Rows(Count).Cells(6).Value.ToString
XlRange.Offset(0, 7).Value = DataGridView1.Rows(Count).Cells(7).Value.ToString
XlRange.Offset(0, 8).Value = DataGridView1.Rows(Count).Cells(8).Value.ToString
XlRange.Offset(0, 9).Value = DataGridView1.Rows(Count).Cells(9).Value.ToString
XlRange.Offset(0, 10).Value = DataGridView1.Rows(Count).Cells(10).Value.ToString
XlRange.Offset(0, 11).Value = DataGridView1.Rows(Count).Cells(11).Value.ToString
XlRange.Offset(0, 12).Value = DataGridView1.Rows(Count).Cells(12).Value.ToString
XlRange.Offset(0, 13).Value = DataGridView1.Rows(Count).Cells(13).Value.ToString
XlRange.Offset(0, 14).Value = DataGridView1.Rows(Count).Cells(14).Value.ToString
XlRange.Offset(0, 15).Value = DataGridView1.Rows(Count).Cells(15).Value.ToString
XlRange.Offset(0, 16).Value = DataGridView1.Rows(Count).Cells(16).Value.ToString
XlRange.Offset(0, 17).Value = DataGridView1.Rows(Count).Cells(17).Value.ToString
XlRange.Offset(0, 18).Value = DataGridView1.Rows(Count).Cells(18).Value.ToString
XlRange.Offset(0, 19).Value = DataGridView1.Rows(Count).Cells(19).Value.ToString
XlRange.Offset(0, 20).Value = DataGridView1.Rows(Count).Cells(20).Value.ToString
XlRange.Offset(0, 21).Value = DataGridView1.Rows(Count).Cells(21).Value.ToString
XlRange.Offset(0, 22).Value = DataGridView1.Rows(Count).Cells(23).Value.ToString 'DB Log numbers
XlRange = XlRange.Offset(1, 0)
Next Count
XLApp.DisplayAlerts = False
Wb.Save()
Wb.Close()
Wb = Nothing
ReturnStack.Push(1)
If My.Settings.Database1 <> "" Then
Me.BeginInvoke(CallDataBindToDataGrid)
Wb = XLApp.Workbooks.Open(My.Settings.Database1)
GoTo SaveData
End If
ReturnLabel1:
ReturnStack.Push(2)
If My.Settings.Database2 <> "" Then
Me.BeginInvoke(CallDataBindToDataGrid)
Wb = XLApp.Workbooks.Open(My.Settings.Database2)
GoTo SaveData
End If
ReturnLabel2:
SaveData:
Ws = Wb.Worksheets("Analysis")
Ws.Activate()
Ws.Unprotect()
XlRange = Ws.Range("A10", "AO2009")
XlRange.ClearContents()
XlRange = Ws.Range("A10")
Dim I As Integer
Dim J As Integer
For I = 0 To DataGridView1.RowCount - 2
If DataGridView1.Rows(I).Cells(1).Value.ToString <> "" Then
For J = 0 To DataGridView1.ColumnCount - 1
Ws.Cells(I + 10, J + 1) = DataGridView1(J, I).Value.ToString()
Next
End If
Next
XLApp.DisplayAlerts = False
Wb.Save()
Wb.Close()
Wb = Nothing
Select Case ReturnStack.Peek()
Case 1 : GoTo ReturnLabel1
Case 2 : GoTo ReturnLabel2
End Select
EndSub101:
XLApp.Quit()
XLApp = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
EndThread = "Yes"
End Sub
Я сузил проблему (я думаю) до того, что система не выпускает графику (releasehdc?), Когда я изменяю источник данных в представлении данных. Я думаю, что это тот случай, когда он работает, когда я не изменяю источник данных, и он фактически начинает работать в своем текущем состоянии, но останавливается на полпути! Мне нужно изменить источник данных, чтобы я мог сохранять разные наборы данных в разные файлы Excel.
Я знаю, что я не должен вызывать графику внутри потоков и кросс-потоки, как это (это единственный способ заставить его работать ... вроде), но любая помощь, которую кто-то может оказать, чтобы обойти эту ошибку, была бы очень оценили.
Спасибо
Пол