【问题标题】:How to use Progress bar during loading an xml File如何在加载 xml 文件时使用进度条
【发布时间】:2011-11-11 19:48:56
【问题描述】:

我想在加载远程 xml 文件时显示进度条。我在 Visual C# 2008 Express Edition 中使用 Windows 应用程序窗体。

private void button1_Click(object sender, EventArgs e)
    {
        string text =  textBox1.Text;
        string url = "http://api.bing.net/xml.aspx?AppId=XXX&Query=" + text + "&Sources=Translation&Version=2.2&Market=en-us&Translation.SourceLanguage=en&Translation.TargetLanguage=De";

        XmlDocument xml = new XmlDocument();
        xml.Load(url);

        XmlNodeList node = xml.GetElementsByTagName("tra:TranslatedTerm");

        for (int x = 0; x < node.Count; x++ )
        {
            textBox2.Text = node[x].InnerText;
            progressbar1.Value = x;
        }
    }

以上代码无法显示进度条加载。请给我一些代码。提前致谢

【问题讨论】:

  • 如果(看起来)之后您不需要内存中的文档,您可能需要考虑使用XmlReader 并在阅读文档时填写文本框。这样会更有效率。
  • 我扩大了答案,因为我意识到我可能会错过我真正想做的事情。

标签: c# progress-bar


【解决方案1】:

您希望进度条具体反映什么?是下载文件(因为它很大)还是处理文件?

进度条反映处理文件

您的进度条不会改变,因为您的方法是同步的 - 在它结束时不会发生任何其他事情。 BackgroundWorker 类专为此类问题而设计。它以异步方式完成主要工作,并且能够报告进度已更改。以下是如何更改游览方式以使用它:

private void button1_Click(object sender, EventArgs e)
{
    string text =  textBox1.Text;
    string url = "http://api.bing.net/xml.aspx?AppId=XXX&Query=" + text + "&Sources=Translation&Version=2.2&Market=en-us&Translation.SourceLanguage=en&Translation.TargetLanguage=De";

    XmlDocument xml = new XmlDocument();
    xml.Load(url);
    XmlNodeList node = xml.GetElementsByTagName("tra:TranslatedTerm");

    BackgroundWorker worker = new BackgroundWorker();

    // tell the background worker it can report progress
    worker.WorkerReportsProgress = true;

    // add our event handlers
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.RunWorkerCompleted);
    worker.ProgressChanged += new ProgressChangedEventHandler(this.ProgressChanged);
    worker.DoWork += new DoWorkEventHandler(this.DoWork);

    // start the worker thread
    worker.RunWorkerAsync(node);
}

现在,主要部分:

private void DoWork(object sender, DoWorkEventArgs e)
{
   // get a reference to the worker that started this request
   BackgroundWorker workerSender = sender as BackgroundWorker;

   // get a node list from agrument passed to RunWorkerAsync
   XmlNodeList node = e.Argument as XmlNodeList;

   for (int i = 0; x < node.Count; i++)
   {
       textBox2.Text = node[i].InnerText;
       workerSender.ReportProgress(node.Count / i);
   }
}

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // do something after work is completed     
}

public void ProgressChanged( object sender, ProgressChangedEventArgs e )
{
    progressBar.Value = e.ProgressPercentage;
}

反映下载文件的进度条

尝试使用HttpWebRequest 将文件作为流获取。

// Create a 'WebRequest' object with the specified url. 
WebRequest myWebRequest = WebRequest.Create(url); 

// Send the 'WebRequest' and wait for response.
WebResponse myWebResponse = myWebRequest.GetResponse(); 

// Obtain a 'Stream' object associated with the response object.
Stream myStream = myWebResponse.GetResponseStream();

long myStreamLenght = myWebResponse.ContentLength;

所以现在您知道了这个 XML 文件的长度。然后你必须从流中异步读取内容(BackgroundWorkerStreamReader 是个好主意)。使用myStream.PositionmyStreamLenght 计算进度。

我知道我不是很具体,但我只是想为您指明正确的方向。我认为在这里写所有这些东西是没有意义的。这里有一些链接可以帮助您处理StreamBackgroundWorker

【讨论】:

    【解决方案2】:

    进度条在这里不起作用,因为这都是“同步”代码。 Click 事件阻止 UI 更新。

    有两种解决方案。

    您可以创建一个后台线程来处理 XML 文件,后台线程将进度报告给前台。我建议使用BackgroundWorker,但在你这样做之前还有很多东西要学。

    一个更简单的解决方案,虽然不是最佳的,是在每次进度更新后通过调用Application.DoEvents() 来刷新表单。这应该只被视为一种短期解决方案,因为如果任务不快,那么您的应用程序可能会出现冻结。

    这两种解决方案都有一个缺点 - 当您的进度条被刷新时,您的应用程序也会处理任何事件。因此,您必须在处理任务时手动禁用 UI,并在完成后重新启用它。

    不久前,我为这个问题创建了一个可重复使用的解决方案。我创建了一个接受委托的“ProgressDialog”。进度对话框执行委托,捕获进度,更新进度条,甚至计算剩余时间。使用 ProgressDialog 的好处是我可以在“模态”模式下显示对话框,这会阻止对主 UI 的访问,甚至阻止 Click 事件完成。
    不幸的是,我没有任何代码可以分享,只有想法。

    【讨论】:

      【解决方案3】:

      问题是你正在使用窗口线程,并且窗口不能被重绘,直到你完成button1_Click。

      使用BackgroundWorker,可以通过调用backgroundworker.ReportProgress来报告进度

      【讨论】:

        【解决方案4】:

        首先,您可能看不到它的速度太快 - 如果您正在测试它,请尝试在其中放置一个睡眠,但进一步,它不更新的原因是您正在处理并且发生在同一个线程上主 UI 正在使用。

        您可以通过调用 Application.DoEvents() 让程序处理所有事件,但这样做,您还可以重新处理用户可能点击的任何内容(包括此按钮) - 因此,如果您想要 DoEvents 并确保您没有'不结束处理额外的工作,当方法启动时禁用表单。

        话虽如此,更好的模型是线程化您的工作并在计时器或回调上更新进度条。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多