簡體   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