0

Нужно обновить значение Label в процессе выполнения обработчика Button.
Пробую так:

private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
    Dispatcher.BeginInvoke(DispatcherPriority.Background,new Action(() =>
    {
        this.ProgressBarLabel.Content = "Поиск всех файлов";
    }));
    SomeProcess();
    MessageBox.Show("Работа завершена");
}

Исключений не возникает. В момент появления MessageBox значение в Label обновляется. Но до этого момента, форма не отрисовывается, т.е. пока выполняется код на месте SomeProcess форма остается неизменной.
Можно вызвать отрисовку принудительно в момент присвоения Label значения?

  • Не работает. - ни о чем не говорит. Как вы это поняли? Исключение возникает? Какое? в процессе выполнения обработчика Button - показывайте код обработчика. Вообще это странный код, непонятно, зачем понадобился диспетчер, объясните пожалуйста. Отредактируйте вопрос, сейчас в нем нет того, что позволило бы дать ответ. Можете хоть класс целиком вставить, в дополнение к тому что уже есть и рассказать кратко, что к чему в нём. – aepot Jan 19 '23 at 07:53
  • На заметку: Label в WPF не используют. В WPF для отображения текста используют TextBlock. Советую заменить. – aepot Jan 19 '23 at 07:54
  • Дополнил информацию в вопросе, Dispatcher используется в попытке обратиться к потоку запускающему форму, поскольку проблема по которой не обновляется форма я предполагаю в том что поток в котором выполняется обработка кнопки блокирует форму. – Сергей Татевосян Jan 19 '23 at 09:35
  • Здесь достаточно информации -> https://stackoverflow.com/questions/4502037/where-is-the-application-doevents-in-wpf – Виктор Jan 19 '23 at 10:00

1 Answers1

1

Диспетчер здесь не поможет, и вот почему: вы закидываете в UI поток работу, которая встает в очередь. А разгребаться эта очередь будет тогда, когда UI поток освободится. А освободится он тогда в данном случае, когда обработчик события полностью завершит работу.

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

Пусть SomeProcess это синхронный метод, работающий с какими-то структурами данных, и одновременно в других потоках с ними ничего не работает. Так же предположим, что SomeProcess не работает с UI. Тогда прокатит следующее решение - асинхронный метод.

private async void ButtonStart_Click(object sender, RoutedEventArgs e)
{
    ButtonStart.IsEnabled = false;
    try
    {
        ProgressBarLabel.Content = "Поиск всех файлов";
        await Task.Run(SomeProcess); // или await Task.Run(() => SomeProcess()), без разницы
        MessageBox.Show("Работа завершена");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    ButtonStart.IsEnabled = true;
}

Task.Run вереводит выполнения кода метода SomeProcess в другой поток. Обратите внимание, вы не можете работать с контролами из этого потока напрямую. Можно либо через диспетчер, либо с помощью IProgress<T>, либо надо превращать сам метод SomeProcess в асинхронный и избавляться от Task.Run, если есть такая возможность.

Как работать с IProgress<T>, я показывал здесь, здесь, здесь и здесь, и еще много где.

aepot
  • 49,560
  • вместо await Task.Run(SomeProcess); я использую Task.WaitAll(ListTasks); но изменений в label у меня не происходит пока обработчик события не завершит работу, но опять же в момент вызова MessageBox изменения на форме отображаются, хотя по факту событие обработчика еще не завершено- получается каким то образом в процессе выполнения обработчика все таки как то можно обновить UI. – Сергей Татевосян Jan 19 '23 at 11:26
  • @СергейТатевосян тогда вместо Task.WaitAll(ListTasks); надо await Task.WhenAll(ListTasks);, смысл здесь именно в await. Все проблемы с ответом из-за того что из вас код насильно надо вытаскивать. Вы же могли нормально изначально показать настоящий, а не выдуманный код в вопросе? – aepot Jan 19 '23 at 11:43
  • я не могу размещать свой код в публичном доступе согласно политике компании. – Сергей Татевосян Jan 19 '23 at 12:00
  • @СергейТатевосян вы же в комментарии его разместили, и кто умрет от строчки Task.WaitAll? вместо сферического SomeProcess в вакууме? Если ответ был полезен, вы можете его принять. Если бесполезен, нужно больше деталей. – aepot Jan 19 '23 at 12:05
  • @СергейТатевосян но вы меня удивили, что это коммерческий проект. Код больше похож на учебный, первых 3 дней обучения шарпу. Лейбл говорит о переходе с Winforms, обработчики событий клика про незнание об MVVM, привязках данных, командах и т.д. Проблемы с обновлением UI - об отсутствии понимания, что такое асинхронный код и многопоточное программирование. Боязнь выложить фрагмент кода - о незнании, как работает NDA, что есть секретное, а что на каждом углу в интернетах валяется. В общем, это код ученика, но не джуниора, учитесь. Ссылка на асинхронное программирование вверху, в ответе. – aepot Jan 19 '23 at 12:10
  • про MVVM, асинхронное программирование и др. мне известно- это код с инструмента, который нужно было написать на коленке для решения небольшой задачи. С плохим понимаем работы потоков согласен. – Сергей Татевосян Jan 19 '23 at 12:18
  • 1
    @СергейТатевосян вот, покопайтесь, может что-то полезного найдете https://ru.stackoverflow.com/search?q=user%3A373567+%5Bwpf%5D+%5Bmvvm%5D Наколеночный WPF как раз удобнее всего на базе MVVM писать, навык просто нужен. – aepot Jan 19 '23 at 12:18
  • 1
    Асинхронный обработчик решил все проблемы. Спасибо. – Сергей Татевосян Jan 19 '23 at 12:21