事件处理程序不再激发



今天下午我一直在工作,试图使用后台工作人员读取位于我的程序集中的一个相当大的xml文件。它一直运行得很好,直到我决定重命名后台工作人员的对象名。在我构建解决方案后,它告诉我它是成功的。在运行并测试了我的程序后,我注意到后台工作人员的DoWork Event根本拒绝启动。当我将下面的代码添加到Backgroundworker的RunWorkerCompleted事件中时,我得到的只是一个消息框,其中包含一个巨大的"没有"。MessageBox.Show(e.Result + " " + e.Error);将其重新命名为原来的名称也无济于事。所有的代码都是我自己写的,所以这里没有涉及第三方应用程序。

这是我用来设置后台工作人员工作的代码

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事件处理程序。

我认为问题是您从构造函数调用RunWorkerAsync,而ProgressChanged由于表单还不可见而失败。尝试将对RunWorkerAsync的调用移动到窗体的Show事件处理程序

好的,所以问题是DoWork事件处理程序中的一个异常,它被try..catch吞噬

总结您的代码问题:

  • try..catch块占用所有异常并使调试变得困难
  • 从表单构造函数内部调用RunWorkerAsync
  • 在没有正确同步/锁定的情况下从工作线程访问UI线程对象
  • DoWork事件处理程序内部调用CancelAsync

相关内容

  • 没有找到相关文章