2013-09-12 4 views
1

У меня есть интересная дилемма, где мое приложение может работать как консольное приложение или приложение Windows Forms.Перенаправление потока в текстовое поле в реальном времени

Поскольку я не хочу, чтобы написать пролитой нагрузку кода, как это во всем моем приложении:

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 содержал содержимое другого элемента управления текстовым полем, чтобы мое приложение могло читать из этого потока вместо текстового поля напрямую.

Заранее спасибо.

+0

Это разумный дизайн. В инфраструктуру встроены никакие потоки, которые напрямую подключаются к текстовым полям, но вы можете легко реализовать свой собственный подкласс. И, вероятно, есть сторонние решения с множеством функций. –

+0

Возможный дубликат [Bind Console Output to RichEdit] (http://stackoverflow.com/questions/3744668/bind-console-output-to-richedit) –

+0

@HansPassant Я взглянул на указанную вами ссылку и в основном перенаправляет вывод консоли в текстовое поле, что не то, что я ищу. Я хочу приложить поток к текстовому блоку, чтобы в текстовом поле автоматически появлялась любая запись в поток. – Intrepid

ответ

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

     } 

    } 
} 
+0

Хорошо, я попал сюда из [другого вопроса] (http://stackoverflow.com/q/18786802/69809), так что теперь я вижу весь код. Да, это не сработает, как я уже говорил. 'MemoryStream' не является потокобезопасным для совместного использования потоков. Вы должны вырезать «StreamWriter», заменить «MemoryStream» на «ConcurrentQueue » и использовать «Enqueue' /' Dequeue »для работы с буфером FIFO. – Groo

-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 
    } 
} 

не супер элегантный, но он должен работать.

+0

Статический метод затем должен знать, работает ли приложение как консоль или Windows; эта информация доступна только в отдельном экземпляре, содержащем данные приложения. Может ли статический метод получить доступ к данным экземпляра? – Intrepid

+0

@MikeClarke см. Мое редактирование для способа идентифицировать это, не нуждаясь ни в чем другом. :) –

+0

Единственная проблема, которую я вижу, заключается в том, что часть кода Windows не будет знать, какой экземпляр формы использовать, поэтому я хотел использовать Streams в первую очередь. В данных моего приложения есть перечисление, которое я использую, чтобы определить, должно ли приложение запускаться как консоль или Windows, поэтому я бы скорее использовал это. Похоже, мне придется переосмыслить мой дизайн. – Intrepid

 Смежные вопросы

  • Нет связанных вопросов^_^