Leider erlauben weder das DataSet noch der TextWriter/XmlWriter, den Sie mit der WriteXml()-Methode verwenden können, ein "ValueWritten"-Ereignis zu abonnieren, was der sauberste Weg wäre, dies zu tun.
Wenn Sie ABSOLUT einen funktionierenden Fortschrittsbalken haben müssen, der dem Benutzer anzeigt, wie viel XML Sie geschrieben haben, würde ich vorschlagen, dass Sie Ihre eigene XmlWriter-Implementierung ableiten, die ein abonnierbares Ereignis bereitstellt und auslöst, das Sie verwenden können, um Ihren Fortschrittsbalken bei jedem Schreibvorgang anzustoßen. Sie können einen XmlTextWriter in Ihre Implementierung einbinden, um den Schreibvorgang tatsächlich durchzuführen (und ich empfehle Ihnen, dies zu tun), aber Sie können nicht direkt von XmlTextWriter ableiten. Das liegt daran, dass die Methoden, die Sie von XmlTextWriter erweitern werden, nicht virtuell sind, so dass Sie die Implementierung von XmlTextWriter mit der Option new
Stichwort. Die Überladung DataSet.WriteXml(XmlWriter) behandelt dann Ihre Klasse als Basis-XmlWriter, so dass die von Ihnen geschriebenen Methoden, die die Implementierungen von XmlTextWriter verbergen, ignoriert werden.
Andere Überlegungen, die Sie abwägen müssen:
- Die genaue Größe der geschriebenen Datei erfahren Sie erst, wenn Ihr XmlWriter von WriteXml() angewiesen wird, seinen Stream zu schließen(). Daher muss jeder "Bump" eine Art fundierte Schätzung sein.
- Wenn alle Ihre Dateien ungefähr gleich groß sein sollen, können Sie ein durchschnittliches Verhältnis von "Chunk zu Prozent" ermitteln, das dann als "Schritt" dient.
- Sie können auch versuchen, den Prozentsatz des Fortschritts direkt einzustellen, indem Sie den Fortschrittsbalken bei jedem Lesevorgang um einen festen Prozentsatz des verbleibenden Fortschritts verschieben, wodurch er sich asymptotisch auf 100 % zubewegt, diesen Wert aber erst erreicht, wenn Ihr Writer geschlossen ist (und ein Ereignis auslöst, das besagt, dass Sie fertig sind).
- Wie bei allen Ereignissen müssen Sie sicherstellen, dass Sie alle Abonnements für das Ereignis ordnungsgemäß freigeben, wenn entweder der Herausgeber oder der Abonnent entlassen wird.
- Wie bei allen UI-Elementen sollten Sie sicherstellen, dass Sie nicht versuchen, die Handler, die mit dem Fortschrittsbalken arbeiten, außerhalb des UI-Threads aufzurufen. Dies schränkt Ihre Multithreading-Optionen ein, da der Aufruf von WriteXml aus einem anderen Thread dazu führt, dass die Handler in diesem Thread ausgeführt werden. Allerdings müssen Sie dem UI-Thread etwas Prozessorzeit zum Neuzeichnen des Balkens zugestehen, so dass eine einfache Single-Thread-Option ebenfalls nicht funktioniert. Erwägen Sie die Verwendung asynchroner Schreibvorgänge hinter den Kulissen und/oder die Durchführung eines Thread.Yield() nach der Aktualisierung des Fortschrittsbalkens.
EDIT: Da XmlWriter abstrakte Methoden deklariert, die XmlTextWriter implementieren muss, können Sie diese in Ihrer benutzerdefinierten Klasse überschreiben, so dass Sie direkt von XmlTextWriter erben können.
Einige Beispielcodes:
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;
}