事件处理程序不再触发

时间:2011-10-01 16:04:53

标签: c# events event-handling

我今天下午一直在努力尝试使用背景工作者从位于我的程序集中的相当大的xml文件中读取。在我决定重命名backgroundworker的objectname之前,它一直运行良好。在我构建了解决方案后,它告诉我它是成功的。在运行我的程序并对其进行测试后,我注意到后台工作者的DoWork事件完全拒绝开火。当我将下面的代码添加到Backgroundworker的RunWorkerCompleted事件中时,我得到的只是一个包含大量内容的消息框。 MessageBox.Show(e.Result + " " + e.Error);将其重命名为它也没有用。我自己编写了所有代码,因此这里没有涉及第三方应用程序。

以下是我用于设置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();
        }
    }

在其背后的评论中原谅这一理论。我正在以最好的方式解释它。

我的问题是,是否有人可能会看到这可能出错的地方?为什么事件突然不起火?它应该用我的xml文件中的项目填充列表(未更改,在重命名之前正在工作)。运行逐步调试也证明它正在跳过我的doWork事件处理程序。

1 个答案:

答案 0 :(得分:4)

我认为问题在于你是从构造函数调用RunWorkerAsyncProgressChanged由于表单尚未显示而失败。尝试将呼叫转移到RunWorkerAsync到表单的Show事件处理程序。

好的,问题是DoWork阻止<{1}}阻止的try..catch事件处理程序中的异常。

总结代码的问题:

  • try..catch阻止吃掉所有异常并使调试变得困难。
  • 从表单构造函数中调用RunWorkerAsync
  • 从工作线程访问UI线程对象,但没有正确的同步/锁定。
  • CancelAsync事件处理程序内部调用DoWork