事件处理程序不再触发

发布于 2024-12-08 04:54:08 字数 5621 浏览 0 评论 0原文

今天下午我一直在工作,试图使用后台工作者从位于我的程序集中的一个相当大的 xml 文件中读取数据。在我决定重命名后台工作者的对象名之前,它一直运行得很好。在我构建解决方案后,它告诉我它成功了。运行我的程序并对其进行测试后,我注意到后台工作者的 DoWork 事件根本拒绝触发。当我将下面的代码添加到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 事件处理程序。

I have been at work this afternoon trying to use a backgroundworker to read from an pretty large xml File Located in my assembly. It has worked pretty well up till the point I decided to rename the backgroundworker's 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. When I added the code below to the Backgroundworker's RunWorkerCompleted event, all i got was a messagebox containing a big fat nothing. 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

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). Running a step-through debug also proved it was skipping my doWork event handler.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

放肆 2024-12-15 04:54:08

我认为问题是您正在从构造函数调用 RunWorkerAsync 并且 ProgressChanged 由于表单尚不可见而失败。尝试将对 RunWorkerAsync 的调用移至表单的 Show 事件处理程序。

好的,所以问题是 DoWork 事件内的异常被 try..catch吃掉的处理程序。

总结一下代码中的问题:

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

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. Try moving the call to RunWorkerAsync to the form's Show event handler.

OK, so the problem was an exception inside the DoWork event handler that was being eaten up by the try..catch block.

To sum up the issues with your code:

  • try..catch block that eats up all exceptions and makes debugging difficult.
  • Call RunWorkerAsync from inside the form constructor.
  • Access UI thread objects from the worker thread without proper synchronization/locking.
  • Call CancelAsync from inside the DoWork event handler.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文