通过Thread将文件添加到Listbox?

时间:2012-12-12 20:14:31

标签: c# winforms

在我的应用程序中,我想将文件添加到我的列表框中。 如果我的文件不是pcap扩展名,我想将文件路径发送到我的类并将其传送到pcap扩展名,然后将此文件添加到我的列表框中。 如果我选择添加namy文件GUI不响应,直到我的应用程序完成添加或转换此文件,我想知道如何通过线程添加选项来完成所有这些。

private void btnAddfiles_Click(object sender, EventArgs e)
{
    System.IO.Stream stream;
    OpenFileDialog thisDialog = new OpenFileDialog();
    thisDialog.InitialDirectory = (lastPath.Length > 0 ? lastPath : "c:\\");
    thisDialog.Filter = "(*.snoop, *.pcap, *.cap, *.net, *.pcapng, *.5vw, *.bfr, *.erf, *.tr1)" +
        "|*.snoop; *.pcap; *.cap; *.net; *.pcapng; *.5vw; *.bfr; *.erf; *.tr1|" + "All files (*.*)|*.*";
    thisDialog.FilterIndex = 1;
    thisDialog.RestoreDirectory = false;
    thisDialog.Multiselect = true;
    thisDialog.Title = "Please Select Source File";

    if (thisDialog.ShowDialog() == DialogResult.OK)
    {
        if (thisDialog.FileNames.Length > 0)
        {
            lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
        }

        foreach (String file in thisDialog.FileNames)
        {
            try
            {
                if ((stream = thisDialog.OpenFile()) != null)
                {
                    using (stream)
                    {
                        string fileToAdd = string.Empty;
                        Editcap editcap = new Editcap();


                            BackgroundWorker backgroundWorker = new BackgroundWorker();
                            backgroundWorker.WorkerReportsProgress = true;
                            backgroundWorker.DoWork += new DoWorkEventHandler(
                            (s3, e3) =>
                            {
                                if (!editcap.isLibpcapFormat(file))
                                {
                                    fileToAdd = editcap.getNewFileName(file);
                                }
                                else
                                {
                                    listBoxFiles.Items.Add(file);
                                }
                            });

                            backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
                                (s3, e3) =>
                                {
                                    listBoxFiles.Items.Add(fileToAdd);
                                });

                            backgroundWorker.RunWorkerAsync();

                        lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
                    }
                }
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
            }
        }

    }
}

2 个答案:

答案 0 :(得分:2)

您的应用程序正在冻结,因为您在UI线程中做了大量工作。您需要将长时间运行的任务移动到后台线程,然后只需更新UI线程中的UI。

为了做到这一点,你需要做的第一件事就是从你的UI操作中分离你长时间运行的任务。目前你正在混淆这两者,这就是你如何将它映射到BackgroundWorker的混淆。

只要您不需要迭代地更新列表框,并且可以一次性添加所有项目(这就是我期望的列表框),您可以简单地执行您的文件IO在一个地方,将结果添加到某种类型的集合中(此处List可能合适)然后,您可以单独将列表中的所有项目添加到ListBox(或使用数据绑定)。

一旦你做出改变,使用像BackgroundWorker之类的东西就很容易了。填充List的IO工作进入DoWork,在后台运行,然后设置Result。然后,RunWorkerCompleted事件将获取该列表,并将项目添加到ListBox

如果您迫切需要将项目添加到列表框中,那么随着时间的推移,您会看到一个项目,然后是下一个项目等,然后将其视为“报告进度”并使用相关进度内置于BackgroundWorker的报告功能。更新循环内部的进度,并在进度报告的事件处理程序中获取给定的值并将其放入ListBox

这是一个实现:

private void btnAddfiles_Click(object sender, EventArgs e)
{
    System.IO.Stream stream;
    OpenFileDialog thisDialog = new OpenFileDialog();
    thisDialog.InitialDirectory = (lastPath.Length > 0 ? lastPath : "c:\\");
    thisDialog.Filter = "(*.snoop, *.pcap, *.cap, *.net, *.pcapng, *.5vw, *.bfr, *.erf, *.tr1)" +
        "|*.snoop; *.pcap; *.cap; *.net; *.pcapng; *.5vw; *.bfr; *.erf; *.tr1|" + "All files (*.*)|*.*";
    thisDialog.FilterIndex = 1;
    thisDialog.RestoreDirectory = false;
    thisDialog.Multiselect = true;
    thisDialog.Title = "Please Select Source File";

    if (thisDialog.ShowDialog() == DialogResult.OK)
    {
        if (thisDialog.FileNames.Length > 0)
        {
            lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
        }

        BackgroundWorker backgroundWorker = new BackgroundWorker();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.DoWork +=
        (s3, e3) =>
        {
            //TODO consider moving everything inside of the `DoWork` handler to another method
            //it's a bit long for an anonymous method
            foreach (String file in thisDialog.FileNames)
            {
                try
                {
                    if ((stream = thisDialog.OpenFile()) != null)
                    {
                        using (stream)
                        {
                            Editcap editcap = new Editcap();
                            if (!editcap.isLibpcapFormat(file))
                            {
                                string fileToAdd = editcap.getNewFileName(file);
                                backgroundWorker.ReportProgress(0, fileToAdd);
                            }
                            else
                            {
                                backgroundWorker.ReportProgress(0, file);
                            }


                            lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
                        }
                    }
                }

                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }
            }
        };

        backgroundWorker.ProgressChanged +=
            (s3, arguments) =>
            {
                listBoxFiles.Items.Add(arguments.UserState);
            };

        backgroundWorker.RunWorkerAsync();

    }
}

答案 1 :(得分:0)

您可以使用BackgroundWorker执行此操作: 通过工具箱将backgroundWorker添加到表单中。

以:

开头
backgroundWorker.RunWorkerAsync(new string[] {parm1, parm2});

将事件添加到backgroundWorker(属性窗口)

使用DoWork进行计算。然后使用RunWorkerCompleted应用设置。