2011-02-25 77 views
2

我想我最好弄清楚如何去這個錯誤我感到reciving:VB.net跨線程操作無效

跨線程操作無效:控制「ListView1的」從訪問線程不是它創建的線程。

我有一個背景工作即是從Excel工作表中提取單元格,並將它們放入列表視圖。

在形式負載我這樣做:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
    Call createListView() 
End Sub 

Private Sub createListView() 
    ListView1.View = View.Details 
    ListView1.GridLines = True 
    ListView1.FullRowSelect = True 
    ListView1.HideSelection = False 
    ListView1.MultiSelect = False 

    ListView1.Columns.Add("Column Name", 150) 
    ListView1.Columns.Add("Column Number", 150) 
End Sub 

然後我所呼叫的用戶之後BackgroundWorker的選擇了一個文件:

If openFileDialog1.ShowDialog() = DialogResult.OK Then 
     stFilePathAndName = openFileDialog1.FileName 
     ProgressBar1.Style = ProgressBarStyle.Marquee 
     BGWxml2excel = New System.ComponentModel.BackgroundWorker 
     BGWxml2excel.WorkerReportsProgress = True 
     BGWxml2excel.WorkerSupportsCancellation = True 
     BGWxml2excel.RunWorkerAsync() 
End If 

然後我與得到的Excel列計數和值,使得處理我可以用它填充ListView:

Private Sub BGWxml2excel_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGWxml2excel.DoWork 
    Call xml2Excel(stFilePathAndName) 
End Sub 

Private Sub xml2Excel(ByRef theDirOfFile As String) 
    Dim xlsApp As Excel.Application 
    Dim xlsWB As Excel.Workbook 
    Dim xlsSheet As Excel.Worksheet 
    Dim columnCount As Integer = 0 

    xlsApp = New Excel.Application 
    xlsApp.Visible = False 
    xlsApp.DisplayAlerts = False 

    xlsWB = xlsApp.Workbooks.OpenXML(Filename:=theDirOfFile, LoadOption:=XlXmlLoadOption.xlXmlLoadImportToList) 
    xlsSheet = xlsWB.Worksheets(1) 
    xlsSheet.Select() 
    columnCount = xlsSheet.UsedRange.Columns.Count 

    Dim lvi As New ListViewItem 
    Dim x As Integer = 1 

    Do Until x = columnCount + 1 
     lvi.Text = xlsSheet.Cells(1, x).value 
     lvi.SubItems.Add(x) 

     ListView1.Items.Add(lvi) 
     x = x + 1 
    Loop 

    'xlsSheet.SaveAs("c:\_tempExcelFile.xlsx", FileFormat:=51, CreateBackup:=False) 
    xlsWB.Close() 
    xlsApp.Quit()  
End Sub 

的錯誤是在這條線:

ListView1.Items.Add(lvi) 

我該怎麼辦才能糾正這個奇怪的proglem?

謝謝!

大衛

回答

0

的問題是,只有UI線程可以更新UI。因爲您正在向工作人員添加ListView項目,所以您會收到此例外情況。

爲了解決這個問題,你可以將你想要添加到列表視圖中的項目存儲到一個共享變量中(UI線程和你的工作人員都可以訪問的項目),在你的表單上放置一個計時器(所以UI線程命中tick事件處理程序)並在tick處理程序中添加項目。

淡化例如(在C#中,因爲它的速度快了很多對我來說:-)):

private List<ListViewItem> _itemsToBeAdded = new List<ListViewItem>(); 
private readonly object _lockObject = new object(); 

// worker method: 
private void xml2Excel(string input) 
{ 
    // do some processing... 
    ListViewItem lvi = new ListViewItem(); 
    // set up lvi 

    lock(_lockObject) 
    { 
     _itemsToBeAdded.Add(lvi); 
    } 
} 

private void timer1_Tick(object sender, EventArgs e) 
{ 
    lock(_lockObject) 
    { 
     foreach(var item in _itemsToBeAdded) 
     { 
      ListView1.Add(item); 
     } 
    } 
} 
0

只有UI線程才能訪問UI。你的後臺工作人員在另一個線程上。你需要使用.InvokeRequired/.Invoke來回到UI線程。

http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

事件處理程序對後臺工作人員會在主線程上得到提升;你可以安全地改變那裏的用戶界面。但實際上在後臺線程中,您必須調用。像這樣:

Delegate Sub SetTextCallback([text] As String) 

Private Sub SetText(ByVal [text] As String) 

     ' InvokeRequired required compares the thread ID of the 
     ' calling thread to the thread ID of the creating thread. 
     ' If these threads are different, it returns true. 
     If Me.textBox1.InvokeRequired Then 
      Dim d As New SetTextCallback(AddressOf SetText) 
      Me.Invoke(d, New Object() {[text]}) 
     Else 
      Me.textBox1.Text = [text] 
     End If 
    End Sub