在 Windows 窗体中使用 PFX 时出现 InvalidOperationException

发布于 2024-07-15 18:16:06 字数 7930 浏览 5 评论 0原文

我这里有两个例外。 不知道为什么会发生,因为我使用 Form.Invoke 在 UI 线程上运行 UI 更新。 首先,

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Xml;
using System.Windows.Forms;

namespace Toplr
{
    using System.Collections.Specialized;
    using System.Xml.XPath;
    using System.Xml.Linq;
    using System.Text;
    using System.ServiceModel.Web;
    using System.ServiceModel.Syndication;
    using System.Net;
    using System.Web;
    using System.Xml.Schema;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public partial class ToplrForm : Form
    {
        private readonly Uri SearchBase = new Uri(@"http://www.twine.com/feed/atom/entries/");

        private readonly UriTemplate SearchTemplate = new UriTemplate(@"search?type={type}&author={author}");

        public ToplrForm()
        {
            InitializeComponent();
            Exiting = false;
            TaskContext = new TaskManager();
            Items = new AsyncBindingList<Twine>(this);
            twineBindingSource.DataSource = Items;
        }

        private void ToplrForm_Load(object sender, EventArgs e)
        {
        }

        private readonly TaskManager TaskContext;

        private readonly AsyncBindingList<Twine> Items;

        private bool Exiting;

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Close()");
            Close();
        }

        private void ToplrForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show("Exiting = tru");
            Exiting = true;
            //TaskContext.Dispose();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog()
            {
                ValidateNames = true
            };
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                using (var xtw = new XmlTextWriter(sfd.FileName, Encoding.UTF8))
                {
                    var xw = XmlWriter.Create(xtw);
                    xw.WriteStartDocument();
                    xw.WriteStartElement("opml");
                    xw.WriteAttributeString("version", "1.1");
                    xw.WriteStartElement("head");
                    xw.WriteElementString("title", userNameComboBox.Text);
                    xw.WriteEndElement();
                    xw.WriteStartElement("body");
                    foreach (var row in twineDataGridView.SelectedRows)
                    {
                        var twine = (Twine)((DataGridViewRow)row).DataBoundItem;
                        if (twine != null)
                        {
                            xw.WriteStartElement("outline");
                            xw.WriteAttributeString("text", twine.Title);
                            xw.WriteAttributeString("type", "link");
                            xw.WriteAttributeString("url", twine.HtmlAddress);
                            xw.WriteStartElement("outline");
                            xw.WriteAttributeString("text", twine.Title);
                            xw.WriteAttributeString("type", "atom");
                            xw.WriteAttributeString("url", twine.AtomAddress);
                            xw.WriteEndElement();
                            xw.WriteEndElement();
                        }
                    }
                    xw.WriteEndElement();
                    xw.WriteEndElement();
                    xw.WriteEndDocument();
                    xw.Close();
                }
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Copyright (C) 2009 Bent Rasmussen");
        }

        private void accessButton_Click(object sender, EventArgs e)
        {
            var user = userNameComboBox.Text;
            Task.Create(x => ProcessAccount(user));
        }

        public void ProcessAccount(string user)
        {
            this.Invoke((Action)(() =>
            {
                userNameComboBox.Enabled = false;
                accessButton.Enabled = false;
                toolStripStatusLabel1.Text = "Processing...";
            }));

            var param = new NameValueCollection();
            param.Add("type", "Twine");
            param.Add("author", user);
            var source = SearchTemplate.BindByName(SearchBase, param);

            var wc = new WebClient();

            using (var feedStream = wc.OpenRead(source))
            {
                var reader = XmlReader.Create(feedStream);
                var feed = SyndicationFeed.Load(reader);
                int c = 0, i = 0;

                foreach (var item in feed.Items)
                {
                    this.Invoke((Action)(() =>
                    {
                        toolStripProgressBar1.Increment(1);
                        toolStripStatusLabel1.Text = "Processing...";
                    }));

                    if (item.Links.Count != 0)
                    {
                        //try
                        {
                            ProcessTwine(item);
                            i++;
                        }
                        //catch (Exception)
                        {
                            c++;
                        }
                    }
                    if (Exiting)
                        break;
                }
            }

            this.Invoke((Action)(() =>
            {
                userNameComboBox.Enabled = true;
                accessButton.Enabled = true;
            }));
        }

        private Twine ProcessTwine(SyndicationItem item)
        {
            var result = new Twine();
            result.Title = item.Title.Text;
            result.HtmlAddress = item.Links[0].Uri.ToString();
            result.AtomAddress = "";

            var wc = new WebClient();
            var data = wc.DownloadData(result.HtmlAddress);

            var stream = new MemoryStream(data);
            var readerSettings = new XmlReaderSettings()
            {
                ProhibitDtd = false,
                ValidationType = ValidationType.None,
                ValidationFlags = XmlSchemaValidationFlags.None,
            };
            var reader = XmlReader.Create(stream, readerSettings);
            var doc = XDocument.Load(reader);
            var htmlNs = (XNamespace)"http://www.w3.org/1999/xhtml";
            var root = doc.Root;
            var atom = from r in root.Descendants(htmlNs + "head").Descendants(htmlNs + "link")
                       where r.Attribute("rel").Value == "alternate" && r.Attribute("type").Value == "application/atom+xml"
                       select r.Attribute("href");
            foreach (var e in atom)
            {
                if (e.Value != "")
                {
                    result.AtomAddress = e.Value;
                    this.BeginInvoke((Action)(() =>
                    {
                        Items.Add(result);
                        toolStripProgressBar1.Increment(1);
                    }));
                }
                break;
            }

            return result;
        }
    }
}

这会触发此片段上的异常“无法访问已处置的对象”

            this.Invoke((Action)(() =>
            {
                toolStripProgressBar1.Increment(1);
                toolStripStatusLabel1.Text = "Processing...";
            }));

如果此片段被注释掉,我会遇到下一个问题 - 程序级别的 TargetInitationException

其内部异常是InvalidOperationException

代码非常简单,所以实现它应该不难,我只是添加了一些提示以继续前进。

Visual Studio 项目文件

I have two exceptions here. Not sure why they occur because I use Form.Invoke to run UI updates on the UI thread. So first,

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Xml;
using System.Windows.Forms;

namespace Toplr
{
    using System.Collections.Specialized;
    using System.Xml.XPath;
    using System.Xml.Linq;
    using System.Text;
    using System.ServiceModel.Web;
    using System.ServiceModel.Syndication;
    using System.Net;
    using System.Web;
    using System.Xml.Schema;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public partial class ToplrForm : Form
    {
        private readonly Uri SearchBase = new Uri(@"http://www.twine.com/feed/atom/entries/");

        private readonly UriTemplate SearchTemplate = new UriTemplate(@"search?type={type}&author={author}");

        public ToplrForm()
        {
            InitializeComponent();
            Exiting = false;
            TaskContext = new TaskManager();
            Items = new AsyncBindingList<Twine>(this);
            twineBindingSource.DataSource = Items;
        }

        private void ToplrForm_Load(object sender, EventArgs e)
        {
        }

        private readonly TaskManager TaskContext;

        private readonly AsyncBindingList<Twine> Items;

        private bool Exiting;

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Close()");
            Close();
        }

        private void ToplrForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show("Exiting = tru");
            Exiting = true;
            //TaskContext.Dispose();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog()
            {
                ValidateNames = true
            };
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                using (var xtw = new XmlTextWriter(sfd.FileName, Encoding.UTF8))
                {
                    var xw = XmlWriter.Create(xtw);
                    xw.WriteStartDocument();
                    xw.WriteStartElement("opml");
                    xw.WriteAttributeString("version", "1.1");
                    xw.WriteStartElement("head");
                    xw.WriteElementString("title", userNameComboBox.Text);
                    xw.WriteEndElement();
                    xw.WriteStartElement("body");
                    foreach (var row in twineDataGridView.SelectedRows)
                    {
                        var twine = (Twine)((DataGridViewRow)row).DataBoundItem;
                        if (twine != null)
                        {
                            xw.WriteStartElement("outline");
                            xw.WriteAttributeString("text", twine.Title);
                            xw.WriteAttributeString("type", "link");
                            xw.WriteAttributeString("url", twine.HtmlAddress);
                            xw.WriteStartElement("outline");
                            xw.WriteAttributeString("text", twine.Title);
                            xw.WriteAttributeString("type", "atom");
                            xw.WriteAttributeString("url", twine.AtomAddress);
                            xw.WriteEndElement();
                            xw.WriteEndElement();
                        }
                    }
                    xw.WriteEndElement();
                    xw.WriteEndElement();
                    xw.WriteEndDocument();
                    xw.Close();
                }
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Copyright (C) 2009 Bent Rasmussen");
        }

        private void accessButton_Click(object sender, EventArgs e)
        {
            var user = userNameComboBox.Text;
            Task.Create(x => ProcessAccount(user));
        }

        public void ProcessAccount(string user)
        {
            this.Invoke((Action)(() =>
            {
                userNameComboBox.Enabled = false;
                accessButton.Enabled = false;
                toolStripStatusLabel1.Text = "Processing...";
            }));

            var param = new NameValueCollection();
            param.Add("type", "Twine");
            param.Add("author", user);
            var source = SearchTemplate.BindByName(SearchBase, param);

            var wc = new WebClient();

            using (var feedStream = wc.OpenRead(source))
            {
                var reader = XmlReader.Create(feedStream);
                var feed = SyndicationFeed.Load(reader);
                int c = 0, i = 0;

                foreach (var item in feed.Items)
                {
                    this.Invoke((Action)(() =>
                    {
                        toolStripProgressBar1.Increment(1);
                        toolStripStatusLabel1.Text = "Processing...";
                    }));

                    if (item.Links.Count != 0)
                    {
                        //try
                        {
                            ProcessTwine(item);
                            i++;
                        }
                        //catch (Exception)
                        {
                            c++;
                        }
                    }
                    if (Exiting)
                        break;
                }
            }

            this.Invoke((Action)(() =>
            {
                userNameComboBox.Enabled = true;
                accessButton.Enabled = true;
            }));
        }

        private Twine ProcessTwine(SyndicationItem item)
        {
            var result = new Twine();
            result.Title = item.Title.Text;
            result.HtmlAddress = item.Links[0].Uri.ToString();
            result.AtomAddress = "";

            var wc = new WebClient();
            var data = wc.DownloadData(result.HtmlAddress);

            var stream = new MemoryStream(data);
            var readerSettings = new XmlReaderSettings()
            {
                ProhibitDtd = false,
                ValidationType = ValidationType.None,
                ValidationFlags = XmlSchemaValidationFlags.None,
            };
            var reader = XmlReader.Create(stream, readerSettings);
            var doc = XDocument.Load(reader);
            var htmlNs = (XNamespace)"http://www.w3.org/1999/xhtml";
            var root = doc.Root;
            var atom = from r in root.Descendants(htmlNs + "head").Descendants(htmlNs + "link")
                       where r.Attribute("rel").Value == "alternate" && r.Attribute("type").Value == "application/atom+xml"
                       select r.Attribute("href");
            foreach (var e in atom)
            {
                if (e.Value != "")
                {
                    result.AtomAddress = e.Value;
                    this.BeginInvoke((Action)(() =>
                    {
                        Items.Add(result);
                        toolStripProgressBar1.Increment(1);
                    }));
                }
                break;
            }

            return result;
        }
    }
}

This triggers the exception "Cannot access a disposed object" on this fragment

            this.Invoke((Action)(() =>
            {
                toolStripProgressBar1.Increment(1);
                toolStripStatusLabel1.Text = "Processing...";
            }));

If this fragment is commented out, I run into the next problem - a TargetInvocationException on Program level.

The inner exception of this is an InvalidOperationException.

The code is quite simple, so it should not be hard to implement this, I just new a few hints to move on.

Visual Studio project files.

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

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

发布评论

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

评论(1

往日 2024-07-22 18:16:06

如果用户点击退出按钮,就会调用 Close() 方法,并且 UI 开始被拆除。 但是,您的工作代码会继续运行并尝试更新 UI,但它无法再执行此操作。

如果集中所有这些调用:

public void UpdateUI(Action action) {
    if(!Exiting) this.Invoke(action);
}

您可以调用:(

UpdateUI(() =>
        {
            toolStripProgressBar1.Increment(1);
            toolStripStatusLabel1.Text = "Processing...";
        });

等等 - 所有 this.Invoke 调用应使用 UpdateUI 代替)
它应该有效。 另外,使 Exiting 可变。

If the user hits the exit button, the Close() method is called, and the UI starts getting torn down. However, your worker code keeps running and attempts to update the UI, which it can no longer do.

If you centralise all those invoke calls:

public void UpdateUI(Action action) {
    if(!Exiting) this.Invoke(action);
}

you can call:

UpdateUI(() =>
        {
            toolStripProgressBar1.Increment(1);
            toolStripStatusLabel1.Text = "Processing...";
        });

(etc - all the this.Invoke calls should use UpdateUI instead)
and it should work. Also, make Exiting volatile.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文