Is there a TextWriter child class that fires event if text is written?
Asked Answered
C

2

5

I have written a method that accepts a TextWriter as an argument (Usually Console.Out, but not necessarily).

When I call this method, some progress info is written to the TextWriter. However, since this method can run a long time, I want to update my UI with some status information.

Currently, I am using a StringWriter but it does not have any events. So the first time I get a result from the StringWriter is after the method completed.

Now I am searching for a class that inherits from TextWriter and fires an TextChanged event or something like that. I know that this shouldn't be to hard to implement, but I bet the CLR Team already did it for me, I just can't find the appropriate class.

Cassius answered 14/9, 2010 at 11:36 Comment(0)
C
15

If anyone is interested, this is a class that extends the StringWriter() class to fire events after every call to writer.Flush().

I also added the posibillity to automatically call Flush() after every write, since, in my case, a third party component, that did write to the console, didn't do a flush.

Sample usage:

void DoIt()
{
    var writer = new StringWriterExt(true); // true = AutoFlush
    writer.Flushed += new StringWriterExt.FlushedEventHandler(writer_Flushed);

    TextWriter stdout = Console.Out;
    try
    {
        Console.SetOut(writer);
        CallLongRunningMethodThatDumpsInfoOnConsole();
    }
    finally
    {
        Console.SetOut(stdout);
    }
}

Now I can display some status information just in time and don't need to wait for the method to finish.

void writer_Flushed(object sender, EventArgs args)
{
    UpdateUi(sender.ToString());
}

And here is the class:

public class StringWriterExt : StringWriter
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    public delegate void FlushedEventHandler(object sender, EventArgs args);
    public event FlushedEventHandler Flushed;
    public virtual bool AutoFlush { get; set; }

    public StringWriterExt()
        : base() { }

    public StringWriterExt(bool autoFlush)
        : base() { this.AutoFlush = autoFlush; }

    protected void OnFlush()
    {
        var eh = Flushed;
        if (eh != null)
            eh(this, EventArgs.Empty);
    }

    public override void Flush()
    {
        base.Flush();
        OnFlush();
    }

    public override void Write(char value)
    {
        base.Write(value);
        if (AutoFlush) Flush();
    }

    public override void Write(string value)
    {
        base.Write(value);
        if (AutoFlush) Flush();
    }

    public override void Write(char[] buffer, int index, int count)
    {
        base.Write(buffer, index, count);
        if (AutoFlush) Flush();
    }
}
Cassius answered 14/9, 2010 at 15:14 Comment(2)
In my case, I needed to clear the StringWriter buffer after each flush. I added this.GetStringBuilder().Clear(); to the end of the OnFlush() method.Impurity
My Console Application uses WriteLine(). I extended TextWriter directly and found that I don't need to override WriteLine(). Write() is enough. I'm unsure whether this is a general rule you can rely on? Could it be that WriteLine() is automatically routed to Write()?Phosphorous
C
2

There is no such thing in the BCL, but as you've already noticed, this wouldn't be hard to implement.

Good luck.

Courtenay answered 14/9, 2010 at 11:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.