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

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

В основном есть 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.");
        }
    }
}

Есть кнопка Run и пустое текстовое поле.

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

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

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

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

4 ответа

Решение

Начните с создания нового 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, 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));

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

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

Я использую что-то вроде этого для списка:

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

Положил textbox на бланке (multiple lines включен) или текстовая область, то вы можете сделать в вашем цикле

txtOutput.Text += "Progress " + percent + "% completed." + Environment.NewLine();
Другие вопросы по тегам