2012-02-08 35 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,将它们添加到列表中非常简单。