1

我这里有两个例外。不知道为什么会发生,因为我使用 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...";
            }));

如果这个片段被注释掉,我会遇到下一个问题——程序级别的TargetInvocationException

内部异常是InvalidOperationException

代码很简单,所以实现起来应该不难,我只是新的一些提示继续前进。

Visual Studio 项目文件.

4

1 回答 1

2

如果用户点击退出按钮,Close()则调用该方法,并且 UI 开始被拆除。但是,您的工作人员代码会继续运行并尝试更新 UI,但它不能再这样做了。

如果您集中所有这些调用调用:

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

您可以致电:

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

(等等 - 所有的this.Invoke调用都应该使用UpdateUI)并且它应该可以工作。此外,使Exiting挥发性。

于 2009-03-22T07:25:32.247 回答