简体   繁体   English

事件处理程序不再触发

[英]Event handler not firing anymore

I have been at work this afternoon trying to use a backgroundworker to read from an pretty large xml File Located in my assembly. 我今天下午一直在努力尝试使用背景工作者从位于我的程序集中的一个非常大的xml文件中读取。 It has worked pretty well up till the point I decided to rename the backgroundworker's objectname. 在我决定重命名backgroundworker的objectname之前,它一直运行良好。 After I built my solution, it told me it was a success. 在我构建了解决方案后,它告诉我它是成功的。 After running my program and testing it, I noticed that the backgroundworker's DoWork Event refuses to fire at all. 在运行我的程序并对其进行测试后,我注意到后台工作者的DoWork事件完全拒绝开火。 When I added the code below to the Backgroundworker's RunWorkerCompleted event, all i got was a messagebox containing a big fat nothing. 当我将下面的代码添加到Backgroundworker的RunWorkerCompleted事件中时,我得到的只是一个包含大量内容的消息框。 MessageBox.Show(e.Result + " " + e.Error); Renaming it back to what it was also didn't help. 将它重命名为它也没有帮助。 I wrote all the code myself, so there are no third party applications involved here. 我自己编写了所有代码,因此这里没有涉及第三方应用程序。

Here is the code I used to set up the workings with the backgroundworker 这是我用来设置backgroundworker工作的代码

private volatile List<string> listItems = new List<string>();
    private BackgroundWorker _populateListItems = new BackgroundWorker();
    private string currentConnection;
    #endregion
    public frmSettings()
    {
        InitializeComponent();

        //I will be able to track how far the list is populated with the following command.
        _populateListItems.WorkerReportsProgress = true;
        //This will fire if there is an error in the xml file.
        _populateListItems.WorkerSupportsCancellation = true;
        //Assign the job to be done for the backgroundworker
        _populateListItems.DoWork +=new DoWorkEventHandler(_populateListItems_DoWork);
        _populateListItems.ProgressChanged += new ProgressChangedEventHandler(_populateListItems_ProgressChanged);
        //When the worker is finished, the following event will fire: All UI controls will be updated.
        _populateListItems.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_populateListItems_RunWorkerCompleted);

        _populateListItems.RunWorkerAsync();
    }

    void _populateListItems_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        prgProgress.Value = e.ProgressPercentage;
        lblProgress.Text = e.ProgressPercentage.ToString() + "%";
    }

    private void _populateListItems_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //The operation is completed/Cancelled/Erroneous. The list will now be populated with the available information.
        MessageBox.Show(e.Result + " " + e.Error);
        foreach (string item in listItems)
        {
            liConnections.Items.Add(item);
        }

        //This shows the user which connection is currently used.
        lblCurrentSelection.Text = currentConnection;
    }

    private void _populateListItems_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            //The following lines of code are the variables that are going to be used.
            // xReadSettings will make the XmlReader xRead Ignore whitespaces and comments, if any.
            // assemblyExecuted will get information from which assembly gets Executed.
            // filename Will get the filename of the settings.xml file that is going to be used.
            // SettingsStream will open the stream for reading and writing, using the GetManifestResourceStream() method from the currently executed assembly.
            XmlReaderSettings xReadSettings = new XmlReaderSettings();
            Assembly assemblyExecuted = Assembly.GetExecutingAssembly();
            string filename = String.Format("{0}.Settings.xml", assemblyExecuted.GetName().Name);
            Stream settingsStream = assemblyExecuted.GetManifestResourceStream(filename);

            xReadSettings.IgnoreComments = true;
            xReadSettings.IgnoreWhitespace = true;

            //Finally the xmlReader object is created using the settingstream, and its settings.
            //While the stream reads, it checks whether the nodes accessed are elements of the xml file.
            //if it is an element that is accessed, then we check whether the element which is accessed is a connection string to the database
            //if it is a connectionstring to the database, we will check if the connection has a name.
            //if it has a name, we get the name attribute, and add it to our list. The list is volatile, so it will be up to date, because this
            //background thread is updating it.
            //To Update the progress of the backgroundworker, we need to know the amount of elements in the XML File. Xpath will be used for this.
            XmlDocument xdoc = new XmlDocument();
            xdoc.Load(settingsStream);
            XmlNodeList nodes = xdoc.SelectNodes("*"); //Xpath - select all.
            int totalElementsToRead = nodes.Count;
            int totalElementsRead = 0;
            using (XmlReader xRead = XmlReader.Create(settingsStream, xReadSettings))
            {
                while (xRead.Read())
                {
                    if (xRead.NodeType == XmlNodeType.Element)
                    {
                        if (xRead.Name == "ConnectionString")
                        {
                            if (xRead.HasAttributes)
                            {
                                string attribute = xRead.GetAttribute("name").ToString();
                                listItems.Add(attribute);
                            }
                        }
                        if (xRead.Name == "CurrentConnection")
                        {
                            xRead.Read(); //gets the value of <CurrentConnection>
                            currentConnection = xRead.Value.Trim();
                        }
                        totalElementsRead++;
                        _populateListItems.ReportProgress(totalElementsRead / totalElementsToRead * 100);
                    }
                }
            }
        }
        catch
        {
            _populateListItems.CancelAsync();
        }
    }

Pardon the theory in the comments behind it. 在其背后的评论中原谅理论。 I'm explaining it the best way that i can. 我正在以最好的方式解释它。

My question is though, can anyone see perhaps where this has gone wrong? 我的问题是,是否有人可能会看到这出错的地方? Why the event suddenly does not fire? 为什么事件突然不起火? It is supposed to fill a list up with items from my xml file (untouched, was working before rename). 它应该用我的xml文件中的项目填充列表(未更改,在重命名之前正在工作)。 Running a step-through debug also proved it was skipping my doWork event handler. 运行逐步调试也证明它正在跳过我的doWork事件处理程序。

I think the problem is that you are calling RunWorkerAsync from the constructor and the ProgressChanged fails due to the form not being visible yet. 我认为问题是你从构造函数调用 RunWorkerAsync ,并且 ProgressChanged由于窗体不可见而失败。 Try moving the call to RunWorkerAsync to the form's Show event handler. 尝试将对 RunWorkerAsync的调用移动到窗体的 Show事件处理程序。

OK, so the problem was an exception inside the DoWork event handler that was being eaten up by the try..catch block. 好的,所以问题是DoWork事件处理程序中的一个异常,它被try..catch占用了。

To sum up the issues with your code: 总结一下代码的问题:

  • try..catch block that eats up all exceptions and makes debugging difficult. try..catch块,它会占用所有异常并使调试变得困难。
  • Call RunWorkerAsync from inside the form constructor. 从表单构造函数中调用RunWorkerAsync
  • Access UI thread objects from the worker thread without proper synchronization/locking. 从工作线程访问UI线程对象,没有正确的同步/锁定。
  • Call CancelAsync from inside the DoWork event handler. DoWork事件处理程序内部调用CancelAsync

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

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