I'm trying to implement routing the Console output for part of the application into a TextBox. The problem is similar to Elegant Log Window in WinForms C# except that I want to capture all the output from a different stream (the Console output) and show it in the text box instead of explicitly calling a logger method.
My plan was to implement this with a System.IO.Pipes.PipeStream. The Console output would be rerouted as input to the PipeStream. The output from the PipeStream would be read at regular intervals (say once per second) from a timer on the form, and updated to the TextBox, discarding old text to stay under a certain character limit but allowing the user to scroll back say 200 lines.
I initialize the PipeStreams like this:
private void initPipelines()
{
pipeServer = new AnonymousPipeServerStream();
pipeClient = new AnonymousPipeClientStream(pipeServer.GetClientHandleAsString());
textWriter_ = new StreamWriter(pipeServer);
textReader_ = new StreamReader(pipeClient);
textWriter_.AutoFlush = true;
}
The routine running once per second to update the text in the TextBox looks like this:
private void updateText()
{
// Get the characters written since the last update
// I tried this but it always waits:
// string message = textReader_.ReadToEnd();
// I tried this but it also waits when there are fewer than 1024 characters available:
int messageLength = textReader_.ReadBlock(buffer, 0, 1024);
string message = new string(buffer, 0, messageLength);
// ... Add the message to the text box and get rid of old text ...
}
In my test routine I simply made a second timer that writes text to the textWriter_ ever 100 to 250 ms.
My problem is that the call to textReader_.ReadToEnd() simply waits, apparently because the textWriter_ stream is still open, and a call to textReader_.ReadBlock also waits if there aren't as many characters to read as will fill the buffer.
What I would like is to have a method for the pipeline that simply reads all the available characters and returns immediately, but I've been unable to find such a function. Is there a way to do this? Or is there some way to determine how many characters would be immediately available?
I need to get the console output character by character, not line-based, since some of the output are "poor man's progress bars" outputting X's to the screen to document progress of the application. All of that is something I can't easily influence.
I thought it would be better to use a System class to accomplish the buffering between the two streams instead of trying to roll my own, but I'm starting to think it might be the only way to do it.