#c# #wpf #multithreading #wpf-controls #backgroundworker
#c# #wpf #многопоточность #wpf-элементы управления #backgroundworker
Вопрос:
Привет, у меня есть приложение, в котором одним из заданий будет преобразование Excel и передача всех записей в базу данных.
Итак, это занимает немного времени, потому что я получу и вставлю в базу данных более 7000 строк.
Итак, поскольку эта работа занимает немного времени, более 3 минут, я хотел бы использовать ProgressBar для отчета о ходе выполнения этой работы.
Итак, если я выполняю эту работу в классе, который я создал, как я могу использовать BackgroundWorker для сообщения о ходе выполнения на ProgressBar в моем случае?
Моя цель — быть точным в процентах от того, как продвигается прогресс, и как я могу использовать все это для отчета о прогрессе. Я никогда не работал с BackgroundWorkers.
Я думаю, и это только подсказка, может быть, хорошая или нет, что я сначала получаю количество строк в Excel, делаю это число некоторым Maxvalue в ProgressBar, а затем для каждой строки или через интервал сообщаю о прогрессе.
Это возможно? Как я могу это сделать?
Ответ №1:
Мне нравится использовать привязки для ProgressBar (и практически для всего остального, где это возможно), потому что таким образом вам не нужно беспокоиться о отправке в поток пользовательского интерфейса.
По сути, вы создаете некоторый класс, который реализует INotifyPropertyChanged со свойством progress, к которому вы можете привязать свой ProgressBar. например
public class Task : INotifyPropertyChanged
{
private int _progress = 0;
public int Progress
{
get { return _progress; }
private set
{
if (_progress != value)
{
_progress = value;
OnPropertyChanged("Progress");
}
}
}
public Task(ref ProgressChangedEventHandler progressChangedEvent)
{
progressChangedEvent = (s, e) => Progress = e.ProgressPercentage;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Этот класс использует событие в конструкторе, которое обновит ход выполнения задачи, если оно возникнет, но вы можете обработать изменение хода выполнения любым удобным вам способом, например методом или путем создания свойства Progress public
, так что вы можете просто изменить его произвольно.
Пример использования:
<ProgressBar Minimum="0" Maximum="100" Height="20"
Value="{Binding UpdateTask.Progress, Mode=OneWay}"/>
// The event that should be raised when a progress occurs.
private event ProgressChangedEventHandler UpdateProgressChanged;
// The task the ProgressBar binds to.
private readonly Task _updateTask;
public Task UpdateTask
{
get { return _updateTask; }
}
public MainWindow()
{
// Instatiate task, hooking it up to the update event.
_updateTask = new Task(ref UpdateProgressChanged);
}
private void OnUpdateProgressChanged(int progressPercentage)
{
if (UpdateProgressChanged != null)
{
UpdateProgressChanged(this, new ProgressChangedEventArgs(progressPercentage, null));
}
}
// Simple progress simulation
private void Button1_Click(object sender, RoutedEventArgs e)
{
int progress = 0;
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(0.5) };
timer.Tick = (sSub,eSub) =>
{
progress ;
// Raise progress changed event which in turn will change
// the progress of the task which in turn will cause
// the binding to update which in turn causes the value
// of the ProgressBar to change.
OnUpdateProgressChanged(progress);
if (progress == 100)
{
timer.Stop();
}
};
timer.Start();
}
Комментарии:
1. Хорошо, я, если хочу привязать прогресс того, что я здесь делаю, к progressbar, я использую свойство Progress, верно? Можете ли вы привести пример привязки progressbar к этому свойству?
2. Добавлен пример, также исправлена ошибка в классе task, коструктору необходимо получить событие по ссылке (
ref
ключевое слово).3. Возможно, ваша привязка нарушена , я протестировал это, и это действительно работает.
4. Хорошо, я создал новый проект приложения wPF и взял ваш пример здесь, и протестировал его, и чтобы узнать, обновляется ли значение в progBar, в конце метода OnUpdatedProgressChanged я использовал окно сообщения, чтобы показывать мне значение progressbar каждый раз, когда свойство progress увеличивается, и значение просто не меняется. Значение всегда равно 0, но свойство увеличивается…
5. Как я уже говорил ранее, работает ли привязка , есть ли какие-либо ошибки в окне вывода? Мой код не завершен , я выполняю привязку с использованием DataContext. Если вы не настолько знакомы с привязкой, прочитайте обзор .
Ответ №2:
Вот пример фонового рабочего с прогрессом.
Однако дважды проверьте, чтобы убедиться, что BGW будет работать в вашей ситуации. Если вы управляете Excel через COM-взаимодействие, для этого может потребоваться поток STA (а BGW — это поток MTA, а не STA).
В этом случае вам нужно будет использовать Task
с STA scheduler или ваше собственное руководство Thread
(я настоятельно рекомендую подход, основанный на Task
STA scheduler).
Комментарии:
1. Да, я использую Com-взаимодействие. Итак, подход к задаче, о котором вы говорите, — это тот, о котором упоминается в backgroudn worker со ссылкой progress, верно?
2. Да, за исключением того, что вам придется использовать
StaTaskScheduler
, на который я ссылался.