2009-07-28 2 views
9

Я работаю в C# и WPF, очень новый для обоих.Как отобразить прогресс во время цикла занятости?

У меня есть петля, которая считывает большое количество данных из внешнего источника. Процесс занимает около 20 секунд, и я хочу показать прогресс пользователю. Мне не нужны какие-либо фантастические индикаторы прогресса, поэтому я решил записать свой прогресс на лейбле, который скажет «Шаг 1/1000», затем перейдите на «Шаг 2/1000» и т. Д.

Мой код выглядит примерно так это:

// "count" is the number of steps in the loop, 
// I receive it in previous code 

String countLabel = "/"+count.ToString(); 

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    labelProgress.Content = "Step "+i.ToString()+countLabel 
} 

Однако во время этого анализа экрана «застрял» и прогресс не показывает, как двигаться вперед. Я понимаю это поведение из моего прошлого на C++, где у меня, вероятно, будет отдельный поток, показывающий индикатор выполнения, получающий уведомления из цикла, или некоторую форму repaint/refresh, или принуждение окна/приложения обрабатывать свою очередь сообщений.

Каков правильный способ сделать это на C#? Я не привязан к метке, так что если есть простой прогресс-бар всплывающее окно, я мог бы использовать вместо этого лейбла было бы также быть большим ...

Благодаря

+0

Это может быть Помощь для вас , ** 100% проверено ** http://stackoverflow.com/a/42995210/6863414 –

ответ

11

Переместить работу в BackgroundWorker и используйте метод ReportProgress.

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    worker.ReportProgress((100 * i)/count); 
} 

private void MyWorker_ProgressChanged(object sender, 
    ProgressChangedEventArgs e) 
{ 
    taskProgressBar.Value = Math.Min(e.ProgressPercentage, 100); 
} 
+0

Является ли это потокобезопасным? –

+1

Да, это должно быть. Ваш фоновый рабочий находится только в одном потоке, обновление индикатора выполнения только в потоке пользовательского интерфейса. Любой поток, отличный от потока пользовательского интерфейса, генерирует исключение, если он пытается обновить значение. Таким образом, вы гарантируете безопасность потоков с помощью этого метода. – user7116

2

Пользовательский интерфейс не обновляется из-за того, что ваш текущий поток имеет более высокий приоритет, чем ваш поток пользовательского интерфейса, который будет в конечном счете, установить метку;). Таким образом, пока ваш поток не закончится с вашими материалами, он в конце обновит ваш ярлык.

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

labelProgress.Dispatcher.Invoke(DispatcherPriority.Background, 
        () => labelProgress.Content = string.Format("Step {0}{1}", i, countLabel)); 

Этого огнь до нитки в фоновом режиме и будет получить работу сделанный! Вы также можете попробовать другие DispatcherPriority опционов

PS Я также взял на себя смелость добавить анонимный метод и исправить строку разборе несколько .. надеюсь, что вы не против ..

3
//Create a Delegate to update your status button 
    delegate void StringParameterDelegate(string value); 
    String countLabel = "/" + count.ToString(); 
    //When your button is clicked to process the loops, start a thread for process the loops 
    public void StartProcessingButtonClick(object sender, EventArgs e) 
    { 
     Thread queryRunningThread = new Thread(new ThreadStart(ProcessLoop)); 
     queryRunningThread.Name = "ProcessLoop"; 
     queryRunningThread.IsBackground = true; 
     queryRunningThread.Start(); 
    } 

    private void ProcessLoop() 
    { 
     for (i = 0; i < count; i++) 
     { 
      ... do analysis ... 
      UpdateProgressLabel("Step "+i.ToString()+countLabel); 
     } 
    } 

    void UpdateProgressLabel(string value) 
    { 
     if (InvokeRequired) 
     { 
      // We're not in the UI thread, so we need to call BeginInvoke 
      BeginInvoke(new StringParameterDelegate(UpdateProgressLabel), new object[] { value }); 
      return; 
     } 
     // Must be on the UI thread if we've got this far 
     labelProgress.Content = value; 
    } 
+0

BackgroundWorker предоставляется таким образом, что вам не нужно обрабатывать весь беспорядок нереста из потока. – user7116

+0

@sixlettervariables Значение этого метода заключается в том, что он позволяет вам больше гибкости, чем просто передавать целое число обратно вызывающему абоненту - вы можете делать НИЧЕГО (например, передать сообщение о статусе, например) – ean5533

Смежные вопросы