Изменение свойств элемента в новом потоке

#c# #wpf

Вопрос:

Я пытаюсь реализовать кнопку; которая меняет свою метку на «Вход…», сохраняет эту метку до завершения события, а затем снова меняет свою метку на старую. Но в этом интервале он не должен зависать (в основном поток пользовательского интерфейса будет продолжать выполняться). Какой алгоритм можно выполнить здесь? Я только что использовал этот код, но он не работает ожидаемо:

             Task.Factory.StartNew(() =>
            {

                string old_label = sign_in_button.label.Content;
    

                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input,
                new Action(() => {

                    sign_in_button.label.Content = "Signing in...";
               
                }));

                // Event gets executed here...
                

                sign_in_button.label.Content = old_label;
            });
 

Комментарии:

1. Очевидно, что при доступе к вашему из фонового потока у вас есть две недопустимые операции между потоками sign_in_button . Вы должны всегда обращаться к нему с помощью диспетчера, как вы делали это один раз. Но что именно работает не так, как ожидалось?

2. Это в основном не меняет содержание метки, я также поставил ящик сообщений после определения old_label, и он не был выполнен.

3. Это связано с тем, что первая строка кода обращается к вашей кнопке из фонового потока, который создает исключение. Вы не ждете своей задачи, поэтому исключение «потеряно». Попробуйте, как предлагает @Lingam

Ответ №1:

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

 private async void Button_Click(object sender, RoutedEventArgs e)
    {
        var _dispatcher = App.Current.MainWindow.Dispatcher;
        string old_label = sign_in_button.Content as string;
        sign_in_button.Content = "Signing in...";

        // Event gets executed here...
        await Task.Run(() => signIn(_dispatcher));
        sign_in_button.Content = old_label;
    }

    private void signIn(Dispatcher _dispatcher)
    {
        //THREAD DELAY TEST
        Thread.Sleep(3500);

        _dispatcher.BeginInvoke(() => { sign_in_button.Content = "Changed from another thread"; },DispatcherPriority.Send);

        Thread.Sleep(3500);
    }
 

Комментарии:

1. Верно. Я думаю, что раньше я неправильно понимал, что такое диспетчер. Теперь я понял, как именно он используется. Спасибо.