跨线程操作无效:控制' ListView1'从创建它的线程以外的线程访问

时间:2015-04-29 00:02:59

标签: vb.net

我试图将列表视图项目导出到Excel工作表,每件事情都很完美 但是当我试图在后台工作人员中这样做时,我会遇到这个错误:

类型' System.InvalidOperationException'的例外情况发生在System.Windows.Forms.dll中但未在用户代码中处理

附加信息:跨线程操作无效:控制' ListView1'从创建它的线程以外的线程访问。

我知道如何解决这个问题,请帮帮我:)。

这是我的代码:

Private Sub PictureBox2_Click(sender As Object, e As EventArgs) Handles PictureBox2.Click
    Try
        saveFileDialog1.Filter = "Excel File|*.xlsx"
        saveFileDialog1.Title = "Save an Excel File"
        Application.EnableVisualStyles()
        If saveFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
            If saveFileDialog1.FileName <> "" Then
                PictureBox1.Visible = True
                BackgroundWorker1.RunWorkerAsync()

            End If
        End If
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    saveExcelFile(SaveFileDialog1.FileName)
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    PictureBox1.Visible = False
    MessageBox.Show("DONE !!")
End Sub

Public Sub saveExcelFile(ByVal FileName As String)
    'Try
    Dim xls As New Excel.Application
    Dim sheet As Excel.Worksheet
    Dim i As Integer
    xls.Workbooks.Add()
    sheet = xls.ActiveWorkbook.ActiveSheet
    Dim row As Integer = 1
    Dim col As Integer = 1
    For i = 0 To Me.ListView1.Columns.Count - 1
        sheet.Cells(1, i + 1) = Me.ListView1.Columns(i).Text
    Next
    For i = 0 To Me.ListView1.Items.Count - 1
        For j = 0 To Me.ListView1.Items(i).SubItems.Count - 1 ' here the ERROR !!
            sheet.Cells(i + 2, j + 1) = Me.ListView1.Items(i).SubItems(j).Text
        Next
    Next

    row += 1
    col = 1

    ' for the header 
    sheet.Rows(1).Font.Name = "Microsoft Sans Serif"
    sheet.Rows(1).Font.size = 16
    sheet.Rows(1).Font.Bold = True
    sheet.Rows(1).HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter
    Dim mycol As System.Drawing.Color = System.Drawing.ColorTranslator.FromHtml("#20b2aa")
    sheet.Rows(1).Font.color = mycol
    ' for all the sheet without header
    sheet.Range("a2", "z1000").Font.Name = "Arial"
    sheet.Range("a2", "z1000").Font.Size = 14
    sheet.Range("a2", "z1000").HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter

    sheet.Range("A1:X1").EntireColumn.AutoFit()
    sheet.Range("A1:X1").EntireRow.AutoFit()

    xls.ActiveWorkbook.SaveAs(FileName)
    xls.Workbooks.Close()
    xls.Quit()
    'Catch ex As Exception
    '    MsgBox(ex.Message)
    'End Try
End Sub

hello Enigmativity ......

我做你说的但是我有一个小错误:

类型&#39; System.Runtime.InteropServices.COMException&#39;的例外情况发生在Noor Phone.exe但未在用户代码中处理

其他信息:无法访问该文件。请尝试以下操作之一:

•确保所选文件夹。

•确保包含该文件的文件夹不是只读文件。

•确保文件名不包含以下代码之一:&lt;&gt;? []:|或者*

•确保文件名和路径名不超过128个字符。

这是我编辑后的代码:

 Private Class BgwData
    Public FileName As String
    Public Headers As String()
    Public Data As String()()
End Class
Private Sub PictureBox2_Click(sender As Object, e As EventArgs) Handles PictureBox2.Click
    'Try

    Dim data As New BgwData() With _
{ _
.FileName = SaveFileDialog1.FileName, _
.Headers = _
Me.ListView1.Columns _
    .Cast(Of System.Windows.Forms.ColumnHeader)() _
    .Select(Function(ch) ch.Name) _
    .ToArray(), _
.Data = _
Me.ListView1.Items.Cast(Of ListViewItem)() _
    .Select(Function(lvi) lvi.SubItems _
            .Cast(Of ListViewItem.ListViewSubItem)() _
            .Select(Function(lvsi) lvsi.Text) _
            .ToArray()) _
    .ToArray() _
}

    'BackgroundWorker1.RunWorkerAsync(data)
    SaveFileDialog1.Filter = "Excel File|*.xlsx"
    SaveFileDialog1.Title = "Save an Excel File"
    Application.EnableVisualStyles()
    If SaveFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
        If SaveFileDialog1.FileName <> "" Then
            PictureBox1.Visible = True
            'BackgroundWorker1.RunWorkerAsync()
            BackgroundWorker1.RunWorkerAsync(data)

        End If
    End If
    'Catch ex As Exception
    '    MsgBox(ex.Message)
    'End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    'saveExcelFile(SaveFileDialog1.FileName)
    saveExcelFile(CType(e.Argument, BgwData))
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    PictureBox1.Visible = False
    MessageBox.Show("DONE !!")
End Sub
Private Sub saveExcelFile(ByVal data As BgwData)
    'Public Sub saveExcelFile(ByVal FileName As String)
    'Try
    Dim xls As New Excel.Application
    Dim sheet As Excel.Worksheet
    Dim i As Integer
    xls.Workbooks.Add()
    sheet = xls.ActiveWorkbook.ActiveSheet
    'Dim row As Integer = 1
    'Dim col As Integer = 1
    'For i = 0 To Me.ListView1.Columns.Count - 1
    '    sheet.Cells(1, i + 1) = Me.ListView1.Columns(i).Text
    'Next
    'For i = 0 To Me.ListView1.Items.Count - 1
    '    For j = 0 To Me.ListView1.Items(i).SubItems.Count - 1 ' here the ERROR !!
    '        sheet.Cells(i + 2, j + 1) = Me.ListView1.Items(i).SubItems(j).Text
    '    Next
    'Next

    Dim row As Integer = 1
    Dim col As Integer = 1
    For i = 0 To data.Headers.Length - 1
        sheet.Cells(1, i + 1) = data.Headers(i)
    Next
    For i = 0 To data.Data.Length - 1
        For j = 0 To data.Data(i).Length - 1
            sheet.Cells(i + 2, j + 1) = data.Data(i)(j)
        Next
    Next

    row += 1
    col = 1

    ' for the header 
    sheet.Rows(1).Font.Name = "Microsoft Sans Serif"
    sheet.Rows(1).Font.size = 16
    sheet.Rows(1).Font.Bold = True
    sheet.Rows(1).HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter
    Dim mycol As System.Drawing.Color = System.Drawing.ColorTranslator.FromHtml("#20b2aa")
    sheet.Rows(1).Font.color = mycol
    ' for all the sheet without header
    sheet.Range("a2", "z1000").Font.Name = "Arial"
    sheet.Range("a2", "z1000").Font.Size = 14
    sheet.Range("a2", "z1000").HorizontalAlignment = Excel.XlVAlign.xlVAlignCenter

    sheet.Range("A1:X1").EntireColumn.AutoFit()
    sheet.Range("A1:X1").EntireRow.AutoFit()

    'xls.ActiveWorkbook.SaveAs(FileName)
    xls.ActiveWorkbook.SaveAs(data.FileName)'**HERE THE ERROR**
    xls.Workbooks.Close()
    xls.Quit()

    Marshal.ReleaseComObject(sheet)
    Marshal.ReleaseComObject(xls)

    'Catch ex As Exception
    '    MsgBox(ex.Message)
    'End Try
End Sub

2 个答案:

答案 0 :(得分:0)

您应始终确保在UI线程中访问UI的元素时,否则您可能会遇到您遇到的错误。

避免此问题的最简单方法是分离从UI读取数据的代码和编写Excel文件的代码。

首先定义一个用于保存数据的简单类:

Private Class BgwData
    Public FileName As String
    Public Headers As String()
    Public Data As String()()
End Class

我在表单类中定义了它,因为它不需要在表单外部公开。

现在调用后台工作程序的代码需要更改,以便创建BgwData的实例,填充ListView中的数据以及文件名,然后发送到工人作为其论据。

Dim data As New BgwData() With _
{ _
    .FileName = saveFileDialog1.FileName, _
    .Headers = _
        Me.ListView1.Columns _
            .Cast(Of System.Windows.Forms.ColumnHeader)() _
            .Select(Function(ch) ch.Name) _
            .ToArray(), _
    .Data = _
        Me.ListView1.Items.Cast(Of ListViewItem)() _
            .Select(Function(lvi) lvi.SubItems _
                    .Cast(Of ListViewItem.ListViewSubItem)() _
                    .Select(Function(lvsi) lvsi.Text) _
                    .ToArray()) _
            .ToArray() _
}

BackgroundWorker1.RunWorkerAsync(data)

此代码在PictureBox2_Click中运行,因此仍在UI线程上。

BackgroundWorker1_DoWork方法略有变化,可以像这样调用saveExcelFile

saveExcelFile(CType(e.Argument, BgwData))

saveExcelFile的签名更改为Private Sub saveExcelFile(ByVal data As BgwData)

填充电子表格的代码变为:

Dim row As Integer = 1
Dim col As Integer = 1
For i = 0 To data.Headers.Length - 1
    sheet.Cells(1, i + 1) = data.Headers(i)
Next
For i = 0 To data.Data.Length - 1
    For j = 0 To data.Data(i).Length - 1
        sheet.Cells(i + 2, j + 1) = data.Data(i)(j)
    Next
Next

当然,成为SaveAs方法调用的变化很小:

xls.ActiveWorkbook.SaveAs(data.FileName)

另外,作为附注,请记住,在使用COM对象后也需要释放它们:

Marshal.ReleaseComObject(sheet);
Marshal.ReleaseComObject(xls);

答案 1 :(得分:0)

我找到了所有我需要的答案是在加载表单中添加这行代码

CheckForIllegalCrossThreadCalls = False

感谢您的帮助