WPF - Как обновить ProgressBar на основе прогресса метода из другого класса? - PullRequest
0 голосов
/ 08 апреля 2020

В моем приложении WPF у меня есть ProgressBar, для которого я хотел бы динамически установить свойство Value в зависимости от прогресса, достигнутого в методе другого класса. Однако я не уверен, как это сделать.

Класс и метод, выполняющий эту работу, имеют следующий вид:

public class WorkerClass
{
    public void doSomething(string filePath)
    {
        using (var package = new Package(filePath)) 
        {
            foreach (var item in package) 
            {
                updateMethod(item); //once this method call is complete I want the ProgressBar to update its Value
            }
        }
    }
}

В классе MainWindow.xaml.cs, метод Вызывает беспокойство метод button_Click():

private void btnUpload_Click(object sender, RoutedEventArgs e)
{
    progressBar.Value = 10;

    WorkerClass worker = new WorkerClass();
    worker.doSomething(txtFilePath.Text); //I want the ProgressBar value to update during this method execution

    progressBar.Value = 100;    
}

Я попытался использовать ключевые слова async/await, применить его к методу doSomething(), вернуть объект Task<int> и применить progressBar.Value = await doSomething(), но ProgressBar по-прежнему обновляется синхронно.

1 Ответ

3 голосов
/ 08 апреля 2020

Используйте Progress<T>, чтобы сообщить о прогрессе, и Task.Run, чтобы переместить обработку в фоновый поток.

Если вы не переместите обработка в фоновом потоке, это произойдет в потоке пользовательского интерфейса. Это означает, что поток пользовательского интерфейса занят выполнением вашей обработки и поэтому не может обновить индикатор выполнения (и ваше приложение будет выглядеть замороженным).

Progress<T> позволяет вам определить действие, которое вызывается каждый раз, когда О прогрессе сообщается с использованием метода Report на соответствующем интерфейсе IProgress<T>, который мы будем использовать для обновления индикатора выполнения. Это также гарантирует, что это действие вызывается в потоке пользовательского интерфейса 1 независимо от того, из какого потока вызывается его метод Report. Это означает, что безопасно вызывать Report из нашего фонового потока, и наш индикатор выполнения все равно будет обновляться из потока пользовательского интерфейса.

public class WorkerClass
{
    public void doSomething(string filePath, IProgress<int> progress)
    {
        using (var package = new Package(filePath)) 
        {
            foreach (var item in package) 
            {
                updateMethod(item); //once this method call is complete I want the ProgressBar to update its Value
                progress.Report(...);
            }
        }
    }
}

private async void btnUpload_Click(object sender, RoutedEventArgs e)
{
    progressBar.Value = 10;

    var progress = new Progress<int>(x => progressBar.Value = x);

    string filePath = txtFilePath.Text;
    WorkerClass worker = new WorkerClass();
    await Task.Run(() => worker.doSomething(filePath, progress));

    progressBar.Value = 100;    
}

1 Строго он захватывает текущий SynchronizationContext при его создании и использует его при вызове действия, переданного его конструктору. Если он построен в потоке пользовательского интерфейса, это означает, что действие вызывается в потоке пользовательского интерфейса.

...