Как проверить поток выполнено, затем заполнить индикатор выполнения в C # / WPF - PullRequest
2 голосов
/ 18 февраля 2010

Я просто работаю над своим первым приложением с графическим интерфейсом в Windows.

У меня есть WPF GUI для небольшой утилиты C #, которая копирует файлы. Когда нажимают кнопку для копирования, я явно не хочу, чтобы графический интерфейс зависал. Итак, я запускаю новый поток, чтобы запустить метод, который копирует файлы. Я предполагаю, что пока нахожусь на пути, и нет лучшего способа сделать это в C #?

Теперь у меня есть ProgressBar, который я хочу казаться заполненным, когда поток закончен. (Пока все нормально, неопределенно). Как проверить, когда копирование завершено?

Итак, пока у меня есть:

Thread t = new Thread(delegate() 
{ 
    po.Organise(inputPath, outputPath, recursive); 
});

t.Start();

PBar.IsIndeterminate = true;

И после этого я хочу что-то вроде:

if (t.Done)
{
    PBar.Value = 100;
}

Ответы [ 7 ]

7 голосов
/ 18 февраля 2010

Посмотрите на класс BackgroundWorker. Он поддерживает такие события, как RunWorkerCompleted или ProgressChanged.
Взгляните здесь тоже (речь идет о многопоточности вообще + фоновый работник, опять же).

2 голосов
/ 18 февраля 2010

Как уже говорилось, рассмотрим использование класса BackgroundWorker . Он был разработан для этих ситуаций и предоставляет события, подходящие для того, чего вы пытаетесь достичь.

Используйте событие ProgressChanged, чтобы сообщать о прогрессе, и RunWorkerCompleted, когда задача завершается. Проверьте на странице MSDN примеры кода.

1 голос
/ 18 февраля 2010

Рекомендация: попробуйте поискать "Progress Bar C # " при переполнении стека.

Я думаю, что есть много очень полезных постов, уже подробно описывающих, что вам нужно сделать.

0 голосов
/ 18 февраля 2010

Как общий принципал программирования Windows, вы должны совершать вызовы для обновления пользовательского интерфейса из потока пользовательского интерфейса (того, который обрабатывает сообщения через насос сообщений).

В Windows Forms этот способ был реализован посредством реализации интерфейса ISynchronizeInvoke в классе Control , главным образом путем реализации метода Invoke .

С выпуском .NET 2.0 стало понятно, что необходим более совершенный механизм для перенаправления вызовов в правильный контекст. Вот тут и наступает SynchronizationContext .

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

Таким образом, независимо от того, является ли Windows Forms средой или WPF, один вызов может быть выполнен одинаковым образом в этих контекстах с одинаковым эффектом (маршалинг вызова).

В вашем конкретном случае, поскольку вы используете замыкание (анонимный метод), вы можете воспользоваться тем, что вам доступен SynchronizationContext (через статическое Текущее свойство ) на сайте вызова потока, чтобы обеспечить механизм обратного вызова потока пользовательского интерфейса из фонового потока:

// Get the synchronization context.
// This is in the UI thread.
SynchronizationContext sc = SynchronizationContext.Current;

// Create the thread, but use the SynchronizationContext
// in the closure to marshal the call back.
Thread t = new Thread(delegate()  
{  
    // Do your work.
    po.Organise(inputPath, outputPath, recursive);  

    // Call back using the SynchronizationContext.
    // Can call the Post method if you don't care
    // about waiting for the result.
    sc.Send(delegate()
    {
        // Fill the progress bar.
        PBar.Value = 100;
    });
}); 

// Make the progress bar indeterminate.
PBar.IsIndeterminate = true;

// Start the thread.
t.Start(); 

Обратите внимание: если вас не волнует ожидание результата обратного вызова в потоке пользовательского интерфейса, вы можете вместо этого совершить вызов Post метода , который отправит вызов в пользовательский интерфейс. поток, не дожидаясь завершения этого вызова.

0 голосов
/ 18 февраля 2010

Быстро и легко взломать было бы просто обновить пользовательский интерфейс в конце вашего анонимного метода в вашей теме.Очевидно, что вы не можете обновить его напрямую, но вы можете использовать Dispatcher.Invoke:

Thread t = new Thread(delegate() 
{ 
    po.Organise(inputPath, outputPath, recursive); 
    Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
});

t.Start();
0 голосов
/ 18 февраля 2010

Обернуть блок if (t.Done) собственным методом. Вызовите этот метод из конца вашего рабочего потока.

Кроме того, вы можете присвоить рабочему потоку имя, чтобы его было легче обнаружить в отладчике.

0 голосов
/ 18 февраля 2010

Вам нужен метод обратного вызова. Это должно помочь вам начать.Он использует AsyncCallback, который является лучшим способом решения проблемы такого типа.

Я только что посмотрел пример, который использовал для проекта, и выделил код, специфичный для моего приложения:

System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
{
    // Do your file copy here
});

AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
{
    this.Dispatcher.Invoke(new ThreadStart(delegate (){
    // set progressbar value to 100 here
    }), null);
});

mi.BeginInvoke(ascb, null);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...