listView的跨线程问题

时间:2011-04-11 18:31:09

标签: c# winforms multithreading c#-4.0

确定之前每个人都发布重复让我告诉你我已经看过所有其他帖子和我仍然失去一些说使用代表或后台工作者等...但我怎么能使这个线程安全我想删除文件上它自己的线程。

这是我正在使用的代码。

private void button1_Click(object sender, EventArgs e)
{
    cleanFiles.RunWorkerAsync();
}

private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
{
    if (listView1.CheckedItems.Count != 0)
    {
        // If so, loop through all checked files and delete.
        for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
        {
            string tempDirectory = Path.GetTempPath();
            foreach (ListViewItem item in listView1.CheckedItems)
            {
                string fileName = item.Text;
                string filePath = Path.Combine(tempDirectory, fileName);

                try
                {
                    File.Delete(filePath);
                }
                catch (Exception)
                {
                    //ignore files being in use
                }
            }
        }
        PaintListView(tFile);
        MessageBox.Show("Files removed");
        toolStripStatusLabel1.Text = ("Ready");
    }
    else
    {
        MessageBox.Show("Please put a check by the files you want to delete");
    }
}

3 个答案:

答案 0 :(得分:2)

正如Reed所提到的,您无法从UI线程本身以外的线程访问UI元素。所以,你必须传递一个委托Control.Invoke()来执行UI线程,就像这样

尝试

    private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
    {
        if (listView1.CheckedItems.Count != 0)
        {
            // If so, loop through all checked files and delete.
            for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
            {
                string tempDirectory = Path.GetTempPath();
                foreach (ListViewItem item in listView1.CheckedItems)
                {
                    string fileName = item.Text;
                    string filePath = Path.Combine(tempDirectory, fileName);

                    try
                    {
                        File.Delete(filePath);
                    }
                    catch (Exception)
                    {
                        //ignore files being in use
                    }
                }
            }

            PaintListViewAndSetLabel();
        }
        else
        {
            ShowMessageBox();
        }
    }

    private void ShowMessageBox()
    {
        if(InvokeRequired)
        {
            this.Invoke(new Action(ShowMessageBox), new object[0]);
            return;
        }
        MessageBox.Show("Please put a check by the files you want to delete");
    }

    private void PaintListViewAndSetLabel()
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action(PaintListViewAndSetLabel),new object[0]);
            return;
        }
        PaintListView(tFile);
        MessageBox.Show("Files removed");
        toolStripStatusLabel1.Text = ("Ready");
    }

答案 1 :(得分:0)

问题是您无法直接从后台线程(即:listView1方法内的任何内容)访问ListView(cleanFiles_DoWork)的任何属性。无法在用户界面线程以外的任何线程上访问用户界面控件。

相反,您应该在调用DoWork之前列出要清理的项目列表,然后通过RunWorkerAsync overload taking an object将这些项目传递给方法,并通过DoWorkEventArgs.Argument在方法中检索它。

这将允许您传递要处理的项目列表,在后台处理它们,然后在完成后更新列表。

答案 2 :(得分:0)

使用来自后台工作程序的控件的坏主意,我最近遇到了与TreeView控件相同的问题。因此,对于Windows窗体控件的线程安全调用解决方案是来自microsoft的How-to article。主要的想法是使用控件的InvokeRequired属性检查安全性,如果是必要的话,通过线程安全的Invoke方法运行方法调用。