Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从另一个线程填充listview_C#_.net_Winforms_Multithreading - Fatal编程技术网

C# 从另一个线程填充listview

C# 从另一个线程填充listview,c#,.net,winforms,multithreading,C#,.net,Winforms,Multithreading,我试图从另一个类填充listview,但出现以下错误: “跨线程操作无效:从创建控件“listView1”的线程以外的线程访问该控件。” 在我的类中,我声明我的listview如下: class CheckBlankPages { public String[] pdfFiles { get; set; } ListView _ListVireRef; public int NrCRT = 1; public CheckBlankPages(Str

我试图从另一个类填充listview,但出现以下错误: “跨线程操作无效:从创建控件“listView1”的线程以外的线程访问该控件。”

在我的类中,我声明我的listview如下:

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);
        }
    }
}
using System;
using System.Windows.Forms;

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

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

            if (control.InvokeRequired)
            {
                control.Invoke(new UniversalVoidDelegate(() => ControlInvoke(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.ControlInvoke(listView1, () => listView1.Items.Add("Test"));
    }   
    //...
    }
}
在我的main表单中,我使用以下代码:

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();
        }

有什么问题吗?

在这里进行简单的搜索,会得到许多结果,告诉您不允许从创建控件的线程以外的线程更改GUI控件(跨线程GUI访问)

为此,必须使用
this.Invoke
this.Dispatcher.Invoke
(在WPF中)完成与更新
列表视图相关的所有操作

编辑
比如说

示例代码:

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
    }
}

您正在尝试从后台线程更新GUI线程。您需要在要更新的控件上使用。您可以检查该控件上的
invokererequired
属性,查看是否需要使用
Invoke
来更新控件

通常我是这样做的:

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);
        }
    }
}
using System;
using System.Windows.Forms;

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

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

            if (control.InvokeRequired)
            {
                control.Invoke(new UniversalVoidDelegate(() => ControlInvoke(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.ControlInvoke(listView1, () => listView1.Items.Add("Test"));
    }   
    //...
    }
}
使用系统;
使用System.Windows.Forms;
命名空间TestWinFormsThresding
{
类TestFormControlHelper
{
delegate void UniversalVoidDelegate();
/// 
///从不同线程调用窗体控件操作
/// 
公共静态void ControlInvoke(控件、操作函数)
{
if(control.IsDisposed | | control.Disposing)
返回;
if(control.invokererequired)
{
调用(新的UniversalVoidDelegate(()=>ControlInvoke(控件,函数));
返回;
}
函数();
}
}
公共部分类TestMainForm:Form
{
// ...
//这将从与MainForm线程不同的线程调用
私有void TestFunction()
{
TestFormCotrolHelper.ControlInvoke(listView1,()=>listView1.Items.Add(“测试”);
}   
//...
}
}

当从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);
        }
    }
}
命名空间窗口窗体应用程序1
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
}
无效附加项(字符串[]项)
{
如果(需要调用)
{
调用((MethodInvoker)委托{this.AddItems(items);});
返回;
}
ListViewItem[]范围=(items.Select(item=>newListViewItem(item))).ToArray();
listView1.Items.AddRange(范围);
}
}
}
函数第一次进入另一个线程时,调用invoke,函数只需再次调用自己,这次是在正确的线程上下文中。
实际工作在if()块之后只写一次。

这是一种合理的做法,因为在应用程序中,您通常希望在不中断代码的情况下继续执行ListView更新等

我已经在用户控件之间完成了消息系统,其中包含了我想在后台更新的控件,它可能会变得非常混乱,因为你最终不得不在消息/事件中进行更多的填充/更新,混乱的代码是错误代码,所以我尝试了其他方法

有一个很好的方法,ListView填充/更新的缓慢部分通常是在ListViewItems的创建中,您可以在自己的线程中完全准备这些内容


现在,对于这类应用程序(使用Fill或update ListView,我不需要等待它准备就绪,然后代码才能继续),我的独立线程创建/准备ListViewItems,然后在线程完成后将准备好的项目添加到ListView非常快,因此,最终的ListView更新可以在用户几乎看不到的用户事件上完成。再加上“只添加你能看到的”,这真的是瞬间的。有几个额外的行,所以当滚动开始时,您可以添加更多的行。(你可能已经注意到youtube/facebook/windows图片浏览器都是这样做的)。因为我们已经准备好了ListViewItems,所以将它们添加到列表中非常简单。

我的应用程序是windows窗体,如何使用Invoke方法填充ListView,就像您在windows窗体上使用ISynchronizeInvoke和Dispatcher中的Invoke方法在控件中修改ListView一样。的可能重复项