2012-02-08 63 views
2

我想從另一個類填充列表視圖,但我geting此錯誤: 「跨線程操作無效:控制'listView1'從一個線程以外的線程訪問它被創造的「填充從另一個線程的列表視圖

在我的課堂我宣佈我的列表視圖這樣的:

class CheckBlankPages 
{ 

    public String[] pdfFiles 
    { get; set; } 

    ListView _ListVireRef; 
    public int NrCRT = 1; 


    public CheckBlankPages(String[] pdfFiles = null, ListView listView = null) 
    { 
     this.pdfFiles = pdfFiles; 
     _ListVireRef = listView; 

    } 
    public void StartCheckingPDF() 
    { 
     foreach (string pdf in pdfFiles) 
     { 
      String[] itm = { (NrCRT++).ToString(), pdf }; 
      ListViewItem item = new ListViewItem(itm); 
      _ListVireRef.Items.Add(item); 
     } 
    } 
} 

,在我的MainForm我用這個代碼:

DialogResult rezultat = openFileDialog1.ShowDialog(); 
     if (rezultat == DialogResult.OK) 
     { 

      CheckBlankPages ck = new CheckBlankPages(openFileDialog1.FileNames, listView1); 
      Thread CheckPDFs = new Thread(new ThreadStart(ck.StartCheckingPDF)); 
      CheckPDFs.Start(); 
     } 

什麼是WR翁?

+0

[Cross-thread operation not valid:從其創建線程以外的線程訪問的控件]的可能副本(http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid -control-accessible-from-a-thread-other-the- – quetzalcoatl 2017-02-07 13:25:29

回答

6

通常我在做這樣的:

using System; 
using System.Windows.Forms; 

namespace TestWinFormsThreding 
{ 
    class TestFormCotrolHelper 
    { 
     delegate void UniversalVoidDelegate(); 

     /// <summary> 
     /// Call form controll action from different thread 
     /// </summary> 
     public static void ControlInvike(Control control, Action function) 
     { 
      if (control.IsDisposed || control.Disposing) 
       return; 

      if (control.InvokeRequired) 
      { 
       control.Invoke(new UniversalVoidDelegate(() => ControlInvike(control, function))); 
       return; 
      } 
      function(); 
     } 
    } 

    public partial class TestMainForm : Form 
    { 
    // ... 
    // This will be called from thread not the same as MainForm thread 
    private void TestFunction() 
    { 
     TestFormCotrolHelper.ControlInvike(listView1,() => listView1.Items.Add("Test")); 
    } 
    //... 
    } 
} 
2

這裏就這麼簡單的搜索就帶來了許多成果,告訴你,這是不允許改變從比創建控件(跨線程GUI訪問)的線程以外的線程一個GUI控制。

爲此,與更新ListView相關的所有內容必須使用this.Invokethis.Dispatcher.Invoke(在WPF中)完成。

EDIT
例如this thread here

示例代碼:

private delegate void MyDelegate(string s); 

public void UpdateControl(Control targetControl, string text) 
{ 
    if (targetControl.InvokeRequired) 
    { 
     // THIS IS STILL THE IN THE CONTEXT OF THE THREAD 
     MyDelegate call = new MyDelegate(UpdateControl); 
     targetControl.Invoke(call, new object[] { text }); 
    } 
    else 
    { 
     // do control stuff 
     // THIS IS IN THE CONTEXT OF THE UI THREAD 
    } 
} 
+0

我的應用程序是windows窗體,我怎樣才能使用Invoke方法來填充列表視圖 – XandrUu 2012-02-08 13:51:08

+0

更新了我的答案。 – 2012-02-08 13:53:49

+0

通過使用ISynchronizeInvoke和Dispatcher中的Invoke方法,您可以在窗體控件上修改控件。 – 2012-02-08 13:55:10

1

您嘗試更新從你後臺線程GUI線程。您需要在想要更新的控件上使用Invoke。您可以檢查該控件上的InvokeRequired屬性,以查看您是否需要使用Invoke來更新控件。

0

從非UI線程請求UI操作是不被允許的(或者是一個壞主意)。 所以,最簡單的方法是擺脫了線的,並顯示消息框(都在同一個UI線程)前添加名單。

0

一個絕招,以避免重複碼或故障時,函數無論從UI線程和其他線程調用是:

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 


     void AddItems(string[] items) 
     { 
      if(InvokeRequired) 
      { 
       Invoke((MethodInvoker) delegate { this.AddItems(items); }); 
       return; 
      } 
      ListViewItem[] range = (items.Select<string, ListViewItem>(item => new ListViewItem(item))).ToArray(); 
      listView1.Items.AddRange(range); 
     } 
    } 
} 

函數第一次進入另一個線程時,調用invoke被調用,函數只是簡單地調用自己,這次是在正確的線程上下文中。 實際工作那麼如果()塊後寫下來只有一次。

0

這是做合理的事情,因爲在應用時經常你想要的ListView更新等去無阻礙了你的代碼。

我已經完成了包含控制/用戶控件的用戶控件之間的消息系統,我想在後臺進行更新,並且可能會變得非常混亂,因爲最終不得不消息/事件的數量遠遠超過填充/更新,雜亂的代碼是錯誤的代碼,所以我嘗試了其他方法。

有一個很好的整潔的方式,ListView的填充/更新緩慢的部分通常是在創建ListViewItems的,你可以做好充分準備那些在您自己的線程。

所以,現在,對於這種應用程序(填充或更新ListView,我不需要等待它準備就緒,我的代碼才能繼續),我的單獨線程創建/準備ListViewItems,然後添加準備項目到線程完成時的ListView非常快,所以最終的ListView更新可以在用戶難以察覺的用戶事件上完成。添加到「只添加你可以看到的」,它確實是瞬間的。有了一些額外的行,所以當滾動開始時,你可以添加更多。 (你可能已經注意到youtube/facebook/windows圖片瀏覽器都是這樣做的)。因爲在我們的例子中,我們已經準備好了ListViewItems,將它們添加到列表中非常簡單。