Как сделать так, чтобы пользовательская форма выпускала системную графику (.net) - PullRequest
1 голос
/ 08 марта 2012

Я использую 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.

Я знаю, что я не должен вызывать графику внутри потоков и кросс-потоки, как это (это единственный способ заставить его работать ... вроде), но любая помощь, которую кто-то может оказать, чтобы обойти эту ошибку, была бы очень оценили.

Спасибо Пол

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...