3

我遇到了一个有趣的困境,我的应用程序可以作为控制台应用程序或 Windows 窗体应用程序运行。

因为我不想在我的应用程序中编写大量这样的代码:

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

为了防止这种情况,我决定创建两个方法,我可以在其中传递一个 TextReader 和 TextWriter 实例,然后使用它们来处理输入和输出,例如

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 );

要在控制台窗口中显示一些文本,我只需要执行以下操作:

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

文本神奇地重定向到控制台。

现在,我的问题是如何为 Windows 应用程序做类似的事情?我创建了一个带有只读文本框控件的表单,我希望将其内容_outputStream实时重定向到此文本框。

另外,我希望_inputStream包含另一个文本框控件的内容,以便我的应用程序可以从该流中读取,而不是直接从文本框中读取。

提前致谢。

4

2 回答 2

1

我已经设法通过创建一个ConcurrentStreamWriter继承StreamWriter并使用ConcurrentQueue备份的类BackgroundWorker来处理队列的内容来解决这个问题。

这是我想出的解决方案:

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();

        }

    }
}
于 2013-09-13T06:56:20.903 回答
-1

框架中没有内置这样的东西。与其硬着头皮做,不如简单地添加一个静态帮助方法(在任何地方都可用),只要你想输出一些东西,你就会调用它:

public static void Output(string message)
{
    if ( IsConsoleApp() )
    {
        // process Console input and output
    }
    else
    {
        // process Windows input and output
    }
}

然后,当您希望输出显示时,只需一行:

Utils.Output("Hello, World!");

要确定是否作为控制台运行,您可以使用以下代码:

private static bool? IsConsole = null;
public static void Output(string message)
{
    if (IsConsole == null)
    {
        int width;
        try
        {
            width = Console.WindowWidth;
        }
        catch
        {
            width = 0;
        }
        IsConsole = (width > 0);
    }

    if (IsConsole.Value == true)
    {
        // process Console input and output
    }
    else
    {
        // process Windows input and output
    }
}

不是超级优雅,但应该可以。

于 2013-09-12T13:11:26.783 回答