Перенаправление Console.WriteLine() в текстовое поле

Я создаю это приложение в Visual Studio 2010 с помощью С#.

В основном есть 2 файла, form1.cs(это форма окна) и program.cs(где лежит вся логика).

//form1.cs
public partial class Form1 : Form
{
    //runButton_click function
}

//program.cs
class Program
{
    static void Main()
    {
        while(blah-condition)
        {
            //some calculation
            Console.WriteLine("Progress " + percent + "% completed.");
        }
    }
}

Появляется кнопка "Запуск" и пустое текстовое поле.

Когда пользователь нажимает кнопку "Выполнить", программа program.cs выполняет некоторую задачу и постоянно распечатывает прогресс с помощью Console.WriteLine() на консоли (командной строке).

Вопрос. Как я могу печатать в текстовое поле формы1 вместо печати в командной строке? Мне нужно будет печатать прогресс постоянно без каких-либо действий пользователя.

Спасибо заранее!

Кстати, он не обязательно должен быть текстовым полем, это может быть ярлык или что-то еще, что может принимать текст. Я выбрал текстовое поле, потому что это имеет для меня больше смысла.

Ответ 1

Начните с создания нового TextWriter, который способен записывать в текстовое поле. Это нужно только для переопределения метода Write, который принимает char, но это было бы нечестивым неэффективным, поэтому лучше переписать хотя бы метод с помощью строки.

public class ControlWriter : TextWriter
{
    private Control textbox;
    public ControlWriter(Control textbox)
    {
        this.textbox = textbox;
    }

    public override void Write(char value)
    {
        textbox.Text += value;
    }

    public override void Write(string value)
    {
        textbox.Text += value;
    }

    public override Encoding Encoding
    {
        get { return Encoding.ASCII; }
    }
}

В этом случае я просто принял Control, который может быть Textbox, a Label или что угодно. Если вы хотите изменить его только на Label, это будет нормально.

Затем просто установите вывод консоли в новый экземпляр этого сценария, указав на какой-то текстовое поле или метку:

Console.SetOut(new ControlWriter(textbox1));

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

public class MultiTextWriter : TextWriter
{
    private IEnumerable<TextWriter> writers;
    public MultiTextWriter(IEnumerable<TextWriter> writers)
    {
        this.writers = writers.ToList();
    }
    public MultiTextWriter(params TextWriter[] writers)
    {
        this.writers = writers;
    }

    public override void Write(char value)
    {
        foreach (var writer in writers)
            writer.Write(value);
    }

    public override void Write(string value)
    {
        foreach (var writer in writers)
            writer.Write(value);
    }

    public override void Flush()
    {
        foreach (var writer in writers)
            writer.Flush();
    }

    public override void Close()
    {
        foreach (var writer in writers)
            writer.Close();
    }

    public override Encoding Encoding
    {
        get { return Encoding.ASCII; }
    }
}

Затем, используя это, мы можем сделать:

Console.SetOut(new MultiTextWriter(new ControlWriter(textbox1), Console.Out));

Ответ 2

Я использую sth для этого списка:

    public class ListBoxWriter : TextWriter //this class redirects console.writeline to debug listbox
{
    private readonly ListBox _list;
    private StringBuilder _content = new StringBuilder();

    public ListBoxWriter(ListBox list)
    {
        _list = list;
    }

    public override Encoding Encoding
    {
        get { return Encoding.UTF8; }
    }
    public override void Write(char value)
    {
        base.Write(value);
        _content.Append(value);

        if (value != '\n') return;
        if (_list.InvokeRequired)
        {
            try
            {
                _list.Invoke(new MethodInvoker(() => _list.Items.Add(_content.ToString())));
                _list.Invoke(new MethodInvoker(() => _list.SelectedIndex = _list.Items.Count - 1));
                _list.Invoke(new MethodInvoker(() => _list.SelectedIndex = -1));
            }
            catch (ObjectDisposedException ex)
            {
                Console.WriteLine(Resources.Exception_raised + " (" + ex.Message + "): " + ex);
            }
        }
        else
        {
            _list.Items.Add(_content.ToString());
            _list.SelectedIndex = _list.Items.Count - 1;
            _list.SelectedIndex = -1;
        }
        _content = new StringBuilder();
    }
}

и в моем основном приложении:

_writer = new ListBoxWriter(DebugWin); // DebugWin is the name og my listbox

Console.SetOut(_writer);

Ответ 3

Не знаю, будет ли это работать, но вы можете попробовать перенаправить вывод консоли.

Используйте Console.SetOut() и создайте производную от TextWriter, которая переопределяет метод WriteLine() и просто назначает параметр метода вашему TextBox.Text Должен работать.

Ответ 4

поместите textbox в форму (multiple lines enabled) или текстовую область, которую вы можете сделать в своем цикле

txtOutput.Text += "Progress " + percent + "% completed." + Environment.NewLine();