繁体   English   中英

后台工作者锁定主线程-Windows Forms C#

[英]Background Worker Locking Main Thread - Windows Forms C#

我有一个后台工作人员,可用于在后台创建文件。 我可以使用它,以便创建文件,并且UI仍然响应。 我进行了一些更改,但现在我不知道为什么后台工作人员锁定了我的主线程。

这是我的后台工作者方法。 我没有进度更改事件。

private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        if (filecreator_bgw.CancellationPending == true)
        {
            e.Cancel = true;
        }
        else
        {
            myManager.createFiles((SelectedFileTypes) e.Argument);
        }
    }

private void filecreator_bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                //status_label.Text = "Canceled!";
            }
            else if (e.Error != null)
            {
                //status_label.Text = "Error: " + e.Error.Message;
            }
            else
            {
                // Check the file manager object to see if the files were created successfully
                    status_label.Text = "COMPLETE";
                    file_statusLabel.Text = "Files Created: " + DateTime.Now.ToShortTimeString();
                    System.Threading.Thread.Sleep(5000);
                    status_label.Text = "Click Create Files to Begin";
                    createfiles_button.Enabled = true;
            }
        }

这是创建文件的方法。

public void createFiles(SelectedFileTypes x)
        {
            if (string.IsNullOrEmpty(Filename) || (x.isCSV == false && x.isTAB == false && x.isXML == false))
            {
                filesCreated = false;
                return;
            }

            // Declare the streams and xml objects used to write to the output files
            XDocument xmlFile;
            StreamWriter swCSV;
            StreamWriter swTAB;

            CSVFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
                Path.GetFileNameWithoutExtension(Filename) + "CSV_TEST.csv";
            swCSV = new StreamWriter(CSVFilename);

            TABFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
                Path.GetFileNameWithoutExtension(Filename) + "TAB_TEST.csv";
            swTAB = new StreamWriter(TABFilename);

            XMLFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
                Path.GetFileNameWithoutExtension(Filename) + "XML_TEST.csv";
            xmlFile = new XDocument(
                        new XDeclaration("1.0", "utf-8", "yes"),
                        new XComment("Crosswalk"));
            xmlFile.Add(new XElement("ACCOUNTS"));

            // String array for use when creating xml nodes
            string[] splits;

            // String used to read in a line from the input file
            string line = "";

            // Use a try and catch block, if any errors are caught, return false
            try
            {
                // Read each line in the file and write to the output files
                using (StreamReader sr = new StreamReader(Filename))
                {
                    int i = 0;
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (x.isCSV)
                        {
                            swCSV.WriteLine(line.Replace(delim, ","));
                        }
                        if (x.isTAB)
                        {
                            swTAB.WriteLine(line.Replace(delim, "\t"));
                        }
                        if (x.isXML)
                        {
                            if (i <= 0)
                            {
                                i++;
                                continue;
                            }

                            splits = line.Split(new string[] { delim }, StringSplitOptions.RemoveEmptyEntries);
                            xmlFile.Root.Add(
                                new XElement("ACCOUNTS",
                                    from s in header
                                    select new XElement(s, splits[Array.IndexOf(header, header.Where(z => z.Equals(s, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault())])
                                    )
                                );
                        }
                    }

                    // Dispose of all objects
                        swCSV.Close();
                        swCSV.Dispose();
                        swTAB.Close();
                        swTAB.Dispose();
                    if (x.isXML)
                    {
                        //xmlFile.Save(Path.GetFullPath(Filename) + Path.GetFileNameWithoutExtension(Filename) + "_TEST.xml");
                        xmlFile.Save(XMLFilename);
                    }
                }
            }
            catch (Exception)
            {
                filesCreated = false;
                return;
            }

            // Return true if file creation was successfull
            filesCreated = true;
        }

在do work方法中,我构建了一个简单的结构来确定应制作哪种输出文件类型,然后将其传递给该方法。 如果我将创建文件的调用注释掉,则UI仍然没有响应。

在创建文件的方法中,我基于要转换的输入文件来构建文件。 我确实使用LINQ语句来帮助构建XML标记,但是保存标记值的数组很小,取决于所选文件,为3-5个元素。

是否有一个简单的解决方案,还是应该重新设计该方法? 如果必须重新设计,应该牢记哪些事情,以避免锁定主线程。 谢谢

这是我如何调用runworkerasync方法:

    private void createfiles_button_Click(object sender, EventArgs e)
    {
        SelectedFileTypes selVal = new SelectedFileTypes();
        foreach (var structVal in outputformats_checkedListBox.CheckedItems)
        {
            if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
                selVal.isCSV = true;
            if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
                selVal.isTAB = true;
            if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
                selVal.isXML = true;
        }

        // Call the FileManager object's create files method
        createfiles_button.Enabled = false;
        filecreator_bgw.RunWorkerAsync(selVal);
    }

更新:我更新了启动工作程序的调用,然后使用传递到工作程序中的参数创建文件的调用。

您不能直接通过BackgroundWorker与大多数UI控件进行交互。 您需要从UI线程访问outputformats_checkedListBox.CheckedItems ,并将生成的SelectedFileTypes对象作为参数传递给BackgroundWorker

另外,请注意,您的取消逻辑确实没有做太多事情。 为了使其正常工作,您需要在整个过程中(而不只是在启动时)检查CancellationPending

这是有关如何启动工作程序的粗略示例:

private void StartWorker()
{
    SelectedFileTypes selVal = new SelectedFileTypes();
    foreach (var structVal in outputformats_checkedListBox.CheckedItems)
    {
        if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
            selVal.isCSV = true;
        if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
                selVal.isTAB = true;
        if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
            selVal.isXML = true;
    }
    filecreator_bgw.RunWorkerAsync(selVal);
}

private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
{
    SelectedFileTypes selVal = (SelectedFileTypes)e.Argument;
    myManager.createFiles(selVal);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM