none
c# Task, async, Winforms, GUI, многопоточность RRS feed

  • Общие обсуждения

  • День добрый.

    Подскажите как правильно использовать эту связку?

    Вот простой пример, есть на форме кнопка и richtextbox, при нажатии на кнопку нужно выполнить определенный метод в отдельном потоке используя Task (как я понимаю task сам работает с пулом потоков) и например внутри этого Task нужно выводить отладочную или другую информацию в тот же richtextbox по мере выполнения этой задачи.

        public partial class Form1 : Form
        {
            public Form1()
            {

                InitializeComponent();
            }

            private Worker _worker;

    private async void button1_Click(object sender, EventArgs e) { await Task.Factory.StartNew(_worker.Work); } public class Worker { private bool _cancelled = false; public void Cancel() { _cancelled = true; } public void Work() { for (int i = 0; i < 10; i++) { if (_cancelled) break; Thread.Sleep(100); //Например тут что-то добавить в richtextbox //richtextbox1.AppendText = "Error ..."; } } }

    }

    Как правильно реализовать "по последний технологии" ?
    30 ноября 2015 г. 9:50

Все ответы

  • Добрый день.

    Конкретно в вашем случае, я бы не использовал Task, а остановился на каком нибудь BackgrounWorker, там в конце есть пример.

    Ну а если на Task, то вот везде, где вам нужно поработать с визуальными компонентами, придется писать вот так:

    //Например тут что-то добавить в richtextbox
    this.BeginInvoke((Action)(() => richtextbox1.AppendText = "Error ..."));

    30 ноября 2015 г. 10:45
    Отвечающий
  • Я думал это можно используя Task и например TaskScheduler передавать контекст и без проблем обращаться к GUI из Task. 

    1 декабря 2015 г. 7:57
  • Добрый день,

    обращаться из одного потока к другому нельзя.

    1 декабря 2015 г. 8:38
  • единственным решением для Task,  это использование Invoke ?
    1 декабря 2015 г. 8:51
  • Теоретически, можно взять Dispatcher потока в котором вам нужно выполнять действия и в нем создавать Task-и. Но, в вашем случае, я бы использовал BasckgorundWorker или BeginInvoke
    1 декабря 2015 г. 8:57
    Отвечающий
  • Добрый день 

    МОжете использовать вот такую реализацию

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            SynchronizationContext synContext;
            public Form1()
            {
                InitializeComponent();
                synContext = SynchronizationContext.Current;
            }
    
            private async void StartButton_Click(object sender, EventArgs e)
            {
                string text = await Task.Run<string>(()=> SomeClass.Work(new object(), cts.Token), cts.Token);
                synContext.Post(delegate { textBox1.Text = text;}, null);
            }
    
            private void CancellButton_Click(object sender, EventArgs e)
            {
               if(cts.Token.CanBeCanceled)
                {
                    cts.Cancel();
                }
            }
        }
    }
    
    class SomeClass
    {
        public static string Work(object o, CancellationToken ct)
        {
            try
            {
                Thread.Sleep(1000);
                ct.ThrowIfCancellationRequested();
                return "Задача завершена успешно";
            }
            catch (Exception ex)
            {
                if (ex is OperationCanceledException)
                {
                    return "Задание было отменено";
                }
                else
                {
                    return "Error";
                }
            }
        }
    }

    1 декабря 2015 г. 12:20