Как изменить label.text, используйте Task.Run () - PullRequest
0 голосов
/ 01 ноября 2018

Без работы await Task.Run():

private async void button2_Click(object sender, EventArgs e)
{
    await Task.Run(() => {
        monitor_r(label1);
    });
}

protected async Task monitor_r(Label L1)
{
    MessageBox.Show(L1.Name);
    L1.ForeColor = Color.Blue;
    L1.Text = "test";
}

Эти команды

MessageBox.Show(L1.Name); 

и

L1.ForeColor = Color.Blue;  

отлично работает но

L1.Text = "test"; 

не работает .

Можете ли вы помочь, почему бы не заменить Label Text?

Ответы [ 3 ]

0 голосов
/ 01 ноября 2018

Если вы хотите создать отдельную ветку, попробуйте это с помощью BackgroundWorker. Вы можете реализовать ReportProgress, если у вас есть цикл.

private void button1_Click(object sender, EventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker()
        {
            WorkerReportsProgress = true,
            WorkerSupportsCancellation = true
        };
        worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
        worker.RunWorkerAsync();                
    }

    private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show(label1.Name);
        label1.ForeColor = Color.Blue;
        label1.Text = "test";
    }
0 голосов
/ 01 ноября 2018

Если вы находитесь в режиме отладки, взгляните на окно вывода. Он должен показывать сообщение об исключении примерно так:

System.InvalidOperationException 'в System.Windows.Forms.dll.

Это потому, что label1 получен доступ из потока, отличного от потока, в котором он был создан. И это вызовет недопустимую многопоточную операцию.

Вы можете решить эту проблему, используя Control.Invoke, как уже упоминал Дмитрий Быченко. Вот простое расширение для выполнения поточно-ориентированных вызовов в Winforms Control.

public static void TryInvoke(this Control control, Action<Control> action)
{
      if (control.InvokeRequired) control.Invoke(new Action(() => action(control)));
      else action(control);
}

Пример использования

label1.TryInvoke(x => x.Text = "test"); 
label1.TryInvoke(x => x.ForeColor = Color.Blue);

Или

this.TryInvoke(x =>
{
     label1.Text = "test";
     label1.ForeColor = Color.Blue;
});

Во-вторых, поскольку вы ничего не ждете в monitor_r, я бы рекомендовал использовать void вместо async Task.

Даже если вы ждете чего-то в monitor_r, вам не нужно

await Task.Run(() => {
        monitor_r(label1);
    });

.. потому что monitor_r само по себе является задачей. Так что просто позвоните await monitor_r(label1);

0 голосов
/ 01 ноября 2018

Попробуйте Control.Invoke : мы должны запустить пользовательский интерфейс Winform в основном потоке только

protected async Task monitor_r(Label L1)
{
    Action action = () => 
    {
        MessageBox.Show(L1.Name);

        L1.ForeColor = Color.Blue;
        L1.Text = "test";
    };

    if (L1.InvokeRequired)
        L1.Invoke(action); // When in different thread
    else 
        action();          // When in the main thread
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...