Search code examples
c#winformsconsoletextreadertextwriter

Redirecting a Stream to a Text Box in real-time


I have got an interesting dilemma where my application can run as a Console App or a Windows Forms App.

Since I do not want to write a shed load of code like this all over my application:

If ( IsConsoleApp() )
{
    // process Console input and output
}
else
{
    // process Windows input and output
}

To prevent this, I have decided to create two methods where I can pass in a TextReader and TextWriter instance and subsequently use these to process input and output, e.g.

public void SetOutputStream( TextWriter outputStream )
{
    _outputStream = outputStream;
}

public void SetInputStream( TextReader inputStream )
{
    _inputStream = inputStream;
}

// To use in a Console App:
SetOutputStream( Console.Out );
SetInputStream( Console.In );

To display some text in the Console window I just need to do something like this:

_outputStream.WriteLine( "Hello, World!");

And the text is magically redirected to the Console.

Now, my issue is how do I do something similar for a Windows application? I have created a form with a read-only Text Box control on it and I want the contents of the _outputStream to be redirected to this text box in real-time.

Also, I want the _inputStream to contain the contents of another Text Box control so that my App can read from this stream instead of the Text Box directly.

Thanks in advance.


Solution

  • I have managed to resolve this by creating a ConcurrentStreamWriter class that inherits StreamWriter and uses a ConcurrentQueue backed up by BackgroundWorker to process the queue's contents.

    This is the solution I have come up with:

    using System;
    using System.Collections.Concurrent;
    using System.ComponentModel;
    using System.IO;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace Quest.Core.IO
    {
        public class ConcurrentStreamWriter : StreamWriter
        {
            private ConcurrentQueue<String> _stringQueue = new ConcurrentQueue<String>();
            private Boolean _disposing;
            private RichTextBox _textBox;
    
            public ConcurrentStreamWriter( Stream stream )
                : base( stream )
            {
                CreateQueueListener();
            }
    
            public ConcurrentStreamWriter( Stream stream, RichTextBox textBox )
                : this( stream )
            {
                _textBox = textBox;
            }
    
            public override void WriteLine()
            {
                base.WriteLine();
                _stringQueue.Enqueue( Environment.NewLine );
            }
    
            public override void WriteLine( string value )
            {
                base.WriteLine( value );
                _stringQueue.Enqueue( String.Format( "{0}\n", value ) );
            }
    
            public override void Write( string value )
            {
                base.Write( value );
                _stringQueue.Enqueue( value );
            }
    
            protected override void Dispose( bool disposing )
            {
                base.Dispose( disposing );
    
                _disposing = disposing;
            }
    
            private void CreateQueueListener()
            {
                var bw = new BackgroundWorker();
    
                bw.DoWork += ( sender, args ) =>
                {
                    while ( !_disposing )
                    {
                        if ( _stringQueue.Count > 0 )
                        {
                            string value = string.Empty;
                            if ( _stringQueue.TryDequeue( out value ) )
                            {
                                if ( _textBox != null )
                                {
                                    if ( _textBox.InvokeRequired )
                                    {
                                        _textBox.Invoke( new Action( () =>
                                        {
                                            _textBox.AppendText( value );
                                            _textBox.ScrollToCaret();
                                        } ) );
                                    }
                                    else
                                    {
                                        _textBox.AppendText( value );
                                        _textBox.ScrollToCaret();
                                    }
                                }
                            }
                        }
                    }
                };
    
                bw.RunWorkerAsync();
    
            }
    
        }
    }