简体   繁体   English

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

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

I have a background worker that I use to create files in the background. 我有一个后台工作人员,可用于在后台创建文件。 I had it working so that the files were created and the UI was still responsive. 我可以使用它,以便创建文件,并且UI仍然响应。 I made some changes and now I can't figure out why the background worker is locking my main thread. 我进行了一些更改,但现在我不知道为什么后台工作人员锁定了我的主线程。

Here are my background worker methods. 这是我的后台工作者方法。 I don't have a progress changed event. 我没有进度更改事件。

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

Here is the method to create the files. 这是创建文件的方法。

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

In the do work method, I build a simple struct to determine what output file types should be made and then I pass it to the method. 在do work方法中,我构建了一个简单的结构来确定应制作哪种输出文件类型,然后将其传递给该方法。 If I comment out that call to create the files, the UI still does not respond. 如果我将创建文件的调用注释掉,则UI仍然没有响应。

In the create files method, I build out the files based on the input file that I am transforming. 在创建文件的方法中,我基于要转换的输入文件来构建文件。 I do use a LINQ statement to help build out XML tags, but the arrays holding the tags values are small, 3-5 elements depending on the file chosen. 我确实使用LINQ语句来帮助构建XML标记,但是保存标记值的数组很小,取决于所选文件,为3-5个元素。

Is there a simple solution, or should I re-design the method. 是否有一个简单的解决方案,还是应该重新设计该方法? If I have to re-design, what are things I should keep in mind to avoid locking the main thread. 如果必须重新设计,应该牢记哪些事情,以避免锁定主线程。 Thanks 谢谢

Here is how I call the runworkerasync method: 这是我如何调用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);
    }

UPDATE: I updated the call to start the worker and then the call to create the files using the argument passed into the worker. 更新:我更新了启动工作程序的调用,然后使用传递到工作程序中的参数创建文件的调用。

You cannot interact with most UI controls directly from a BackgroundWorker . 您不能直接通过BackgroundWorker与大多数UI控件进行交互。 You need to access outputformats_checkedListBox.CheckedItems from the UI thread and pass the resulting SelectedFileTypes object into the BackgroundWorker as a parameter. 您需要从UI线程访问outputformats_checkedListBox.CheckedItems ,并将生成的SelectedFileTypes对象作为参数传递给BackgroundWorker

Also, pleas enote that your cancellation logic really didn't do much. 另外,请注意,您的取消逻辑确实没有做太多事情。 In order for it to work well, you need to check CancellationPending throughout the process, not just when starting. 为了使其正常工作,您需要在整个过程中(而不只是在启动时)检查CancellationPending

Here is a rough example of how you should start the worker: 这是有关如何启动工作程序的粗略示例:

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