我写xml时如何增加进度条?

时间:2011-01-05 17:11:03

标签: c# winforms

我有数据集ds

DataSet ds = new DataSet();
SQL = "SELECT * FROM MyCount";
adp = new SqlCeDataAdapter(SQL, Conn);
adp.Fill(ds, "MyCount");
adp.Dispose();

我写这样的xml:ds.WriteXml(@"\MyPath\Count.xml");

我需要在执行此操作时增加进度条。

怎么做?

感谢

3 个答案:

答案 0 :(得分:5)

不幸的是,您可以使用WriteXml()方法使用的DataSet和TextWriter / XmlWriter都不允许您订阅任何“ValueWritten”事件,这将是最干净的方法。

如果您绝对必须有一个工作进度条,它会向用户显示您编写的XML数量,我建议您派生自己的XmlWriter实现,该实现将公开并触发可用于阻止进度的可订阅事件每次写吧。您可以在实现中包含一个XmlTextWriter来实际编写(我强烈建议这样做),但是您无法直接从XmlTextWriter派生。这是因为您将从XmlTextWriter扩展的方法不是虚拟的,因此您必须使用new关键字隐藏XmlTextWriter的实现。然后,DataSet.WriteXml(XmlWriter)重载会将您的类视为基本XmlWriter,因此您编写的隐藏XmlTextWriter实现的方法将被忽略。

您需要权衡的其他注意事项:

  • 在您通过WriteXml()告诉XmlWriter关闭它的流之前,您不会知道写入文件的确切大小。因此,每个“碰撞”都需要进行某种有根据的猜测。
  • 如果预计所有文件的大小大致相同,则可以提出平均“块到百分比”比率,这将成为您的“步骤”。
  • 您还可以尝试直接设置进度百分比,将进度条按每次读取的剩余进度的某个固定百分比移动,这会将其渐近地移向100%但在作者关闭之前不会到达(并触发事件说你已经完成了。
  • 与所有活动一样,请确保在处理发布者或订阅者时正确释放所有订阅活动。
  • 与所有UI元素一样,请确保您没有尝试调用与UI线程之外的进度条一起使用的处理程序。这限制了您的多线程选项,因为从另一个线程调用WriteXml将导致处理程序在该线程中运行。但是,您必须允许UI线程花费一些处理器时间来重绘条形图,因此扁平单线程选项也不起作用。考虑在幕后使用异步写入,和/或在更新进度条后执行Thread.Yield()。

编辑:实际上,因为XmlWriter声明了XmlTextWriter必须实现的抽象方法,所以你可以在自定义类中进一步覆盖它们,这样你就可以直接从XmlTextWriter继承。

一些示例代码:

public class ObservableXmlTextWriter: XmlTextWriter
{
   public delegate void XmlWriteHandler(object sender, XmlWriteEventArgs e);

   public event XmlWriteHandler XmlWritten;

   public event EventHandler XmlWriteComplete;

   public class XmlWriteEventArgs:EventArgs
   {
      public object Value{get; private set;}
      public XmlWriteEventArgs(object value) {Value = value;}
   }

   public override WriteValue(string value)
   {
      base.WriteValue(value);
      if(XmlWritten != null) XmlWritten(this, new XmlWriteEventArgs(value));
   }

   public override WriteValue(int value)
   {
      base.WriteValue(value);
      if(XmlWritten != null) XmlWritten(this, new XmlWriteEventArgs(value));
   }

   ... //override ALL Write methods to fire XmlWritten as above

   //Dispose will call Close(), so just make sure to do one or the other
   public override Close()
   {
      base.Close(value);
      if(XmlWriteComplete!= null) XmlWriteComplete(this, new EventArgs()));
   }
}

...

public void XmlWriteHandler(object sender, XmlWriteEventArgs e)
{
   //Feel free to come up with your own algorithm for approaching 100%;
   //the number of times this event fires will be proportional to the
   //number of data elements (rows * columns) in the DataSet.
   MyProgressBar.Increment((MyProgressBar.Maximum - MyProgressBar.Value) * .05)
}

public void XmlWriteCompleteHandler(object sender, EventArgs e)
{
   MyProgressBar.Value = MyProgressBar.Maximum;
}

答案 1 :(得分:1)

可以肯定的是,无论您使用标准控件的方式如何,都不会逐字节通知。想想会带来多少开销,特别是当每个人都在努力批量写入时。

您有2种方法可以更新进度条:

  • 为写入设置指定数量的进度条“progress”,并在写入完成后跳过它;它意味着猜测并提供一个非常“滑板”的进度条,特别是如果这个写入是进度条计数的主要部分。
  • 你完全放弃了确定性进度条,而是使用其中一个旋转进度条,即从左到右反复进行的进度条。您可以在Windows中看到相关的一些示例。

答案 2 :(得分:0)

我认为你需要更清楚。 progressBar希望您输入最小值(起始点)和最大值(终点),并希望在performtep()函数中传递多少步骤。如果你说1,它会增加1乘1. PerformStep()会增加你的标准。但如果你想立即看到它,你必须使用

progressBar1.PerformStep();
Application.DoEvents();

通常我在for或foreach循环中使用progressBar。 There is an example of usage:

在你的问题中,我看到你没有任何循环。那么你认为如何使用progressBar?