当前线程必须设置为单线程单元(STA)

时间:2017-05-15 10:12:44

标签: vb.net multithreading

我目前正在制作索引程序。我最近在我的正则表达式中添加了一个搜索文件的方法来检测同一文件中正则表达式的重复项。

问题是我得到了:

  

在进行OLE调用之前,必须将当前线程设置为单线程单元(STA)模式。确保您的Main函数标记了STAThreadAttribute。

当我调用我的导出函数时,会将重复项写入文件。但是我在程序的其他部分多次使用导出函数,之前我从未遇到过这个问题。

简而言之我所做的是:

  1. FormStats.vb

    1.1。正则表达式搜索BackGroundWorker()

    1.2。存储重复项(如果有)

    1.3。致电BackGroundWorker_RunWorkerCompletedExportDoublon()

  2. FileHandler.vb

    2.1。致电WriteDoublon()exportToWord()

  3. Exporter.vb

    3.1。 exportToWord()

  4. 出现错误的行:

    Clipboard.SetText(table) 
    

    FileHandler.vb

    调用类的方式
    Public Sub WriteDoublon(ByVal CurrentDoub As List(Of Doublon))
        Dim dgv As New DataGridView
        dgv.Columns.Add("Name", "Name")
        dgv.Columns.Add("Fiche", "Fiche")
        For Each doublee As Doublon In CurrentDoub
            dgv.Rows.Add(doublee.Name, doublee.Ficher)
            dgv.Rows.Add("**********", "**********")
        Next
        Dim exp As New Exporter
        Dim prog As New ProgressBar
        exp.exportToWord(dgv, AppDomain.CurrentDomain.BaseDirectory & "Exports\Doublon.docx", prog)
    End Sub
    

    FileHandler.WriteDoublon()被称为 FormStats.vb 的地方:

    Public Sub ExportDoublon()
        Dim fl As New FileHandler
        fl.WriteDoublon(Doub)
    End Sub
    

    出现错误的类 Exporter.vb

    Public Sub exportToWord(ByVal dgv As DataGridView, ByVal pather As String, ByVal progresser As ProgressBar)    
        Dim oWord As Word.Application = DirectCast(CreateObject("Word.Application"), Word.Application)
        Dim oDoc As Word.Document = oWord.Documents.Add()
        oWord.Visible = False    
        Dim headers = (From ch In dgv.Columns
                       Let header = DirectCast(DirectCast(ch, DataGridViewColumn).HeaderCell, DataGridViewColumnHeaderCell)
                       Select header.Value).ToArray()
        Dim headerText() As String = Array.ConvertAll(headers, Function(v) v.ToString)
    
        Dim items() = (From r In dgv.Rows
                       Let row = DirectCast(r, DataGridViewRow)
                       Where Not row.IsNewRow
                       Select (From cell In row.Cells
                               Let c = DirectCast(cell, DataGridViewCell)
                               Select c.Value).ToArray()).ToArray()    
        Dim table As String = String.Join(vbTab, headerText) & Environment.NewLine
        Dim i As Integer = 0
        For Each a In items
            Dim t() As String = Array.ConvertAll(a, Function(v) v.ToString)
            table &= String.Join(vbTab, t) & Environment.NewLine
            progresser.Value = i * 100 / items.Count
            i = i + 1
        Next
        table = table.TrimEnd(CChar(Environment.NewLine))
        '--ERROR HERE
        Clipboard.SetText(table)
        '#############    
        Dim oTable As Word.Table = oDoc.Tables.Add(oDoc.Bookmarks.Item("\endofdoc").Range, items.Count + 1, headers.Count)    
        oTable.Range.Paste()    
        'make the first row bold, fs 14 + change textcolor
        oTable.Rows.Item(1).Range.Font.Bold = &H98967E
        oTable.Rows.Item(1).Range.Font.Size = 14
        oTable.Rows.Item(1).Range.Font.Color = Word.WdColor.wdColorWhite    
        'change backcolor of first row
        oTable.Rows.Item(1).Range.Shading.Texture = Word.WdTextureIndex.wdTextureNone
        oTable.Rows.Item(1).Alignment = Word.WdAlignmentTabAlignment.wdCenter
        oTable.Rows.Item(1).Range.Shading.ForegroundPatternColor = Word.WdColor.wdColorAutomatic
        oTable.Rows.Item(1).Range.Shading.BackgroundPatternColor = Word.WdColor.wdColorPaleBlue    
        'set table borders
        With oTable.Range.Tables(1)
            With .Borders(Word.WdBorderType.wdBorderLeft)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth100pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            With .Borders(Word.WdBorderType.wdBorderRight)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth100pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            With .Borders(Word.WdBorderType.wdBorderTop)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth100pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            With .Borders(Word.WdBorderType.wdBorderBottom)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth100pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            With .Borders(Word.WdBorderType.wdBorderHorizontal)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth050pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            With .Borders(Word.WdBorderType.wdBorderVertical)
                .LineStyle = Word.WdLineStyle.wdLineStyleSingle
                .LineWidth = Word.WdLineWidth.wdLineWidth050pt
                .Color = Word.WdColor.wdColorAutomatic
            End With
            .Borders(Word.WdBorderType.wdBorderDiagonalDown).LineStyle = Word.WdLineStyle.wdLineStyleNone
            .Borders(Word.WdBorderType.wdBorderDiagonalUp).LineStyle = Word.WdLineStyle.wdLineStyleNone
            .Borders.Shadow = False
        End With
        oDoc.SaveAs2(pather)
        oDoc.Close()
        oDoc = Nothing
        oWord.Quit()
        oWord = Nothing
        GC.Collect()
        GC.WaitForFullGCComplete()
    End Sub
    

1 个答案:

答案 0 :(得分:2)

您对exportToWord的调用显然是在配置为Threading.ApartmentState.MTA的线程上运行(后台工作线程为Threading.ApartmentState.MTA)。通常当您访问此方法的控件执行datagridview时,您将收到Cross-thread operation not valid错误。但是,此检查仅针对需要控件的Handle属性的此类访问运行;在这种情况下,您正在访问dgv中未触发此检查的数据信息。

如果将以下无意义的语句添加到exportToWord的开头,则应该抛出错误。

Dim handle As IntPtr = dgv.Handle

必须从Clipboard线程访问Threading.ApartmentState.STA,并且UI线程就是这样一个线程。执行此操作的正确方法是在UI线程上使用Invoke方法Me是Form实例:

Me.Invoke(New Action(Of DataGridView, String, ProgressBar)(AddressOf exp.exportToWord), New Object(){dgv, AppDomain.CurrentDomain.BaseDirectory & "Exports\Doublon.docx", prog})

与当前的

相比
exp.exportToWord(dgv, AppDomain.CurrentDomain.BaseDirectory & "Exports\Doublon.docx", prog)