У меня есть c# приложение форм окон, которое я бросил вместе. Это справедливо simple:\
исходные данные:
Приложение перерывает текстовые файлы в исходной папке для строки введенного текста; если это находит строку затем, это копирует тот файл и файл изображения с тем же именем к папке назначения. Это делает это однако много раз на основе целого числа вводило.
Таким образом, у меня есть кнопка, и в событии нажатия кнопки я звоню
ProcessImages(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString());
который является:
private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages)
{
int ImageCounter = 0;
int MaxImages = Convert.ToInt32(strNumImages);
DirectoryInfo di = new DirectoryInfo(SourceFolder);
foreach (FileInfo fi in di.GetFiles("*.txt"))
{
if (fi.OpenText().ReadToEnd().Contains(DID))
{
//found one!
FileInfo fi2 = new FileInfo(fi.FullName.Replace(".txt", ".tif"));
if (fi2.Exists)
{
try
{
tbOutput.Text += "Copying " + fi2.FullName + " to " + tbDest.Text + "\r\n";
fi2.CopyTo(tbDest.Text + @"\" + fi2.Name, true);
tbOutput.Text += "Copying " + fi.FullName + " to " + tbDest.Text + "\r\n";
fi.CopyTo(tbDest.Text + @"\" + fi.Name, true);
ImageCounter++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
if (ImageCounter >= MaxImages)
break;
}
}
То, что происходит, - то, что процесс хорошо работает, но я хочу обновить текстовое поле на форме с прогрессом, поскольку файлы копируются. В основном форма потеряла сознание, в то время как она работает, и после того, как она закончилась, вывод находится в текстовом поле. Я хотел бы реализовать BackgroundWorker, заставляют это обновлять UI, в то время как это работает.
Я просмотрел примеры, но действительно не следую за ними. У меня нет процента полным значением, я просто хочу обновить изменения.Text каждое повторение и иметь его дисплей. Я даже не думаю, что обязательно должен поместить фактическое действие копирования в различные потоки, оно просто кажется, что потребности, которые будут выполнены отдельно от основного UI, распараллеливают. Возможно, я по усложнению этого, в целом... кто-то может продвинуть меня в правильном направлении?Спасибо!
Если вы используете фоновый рабочий процесс, вы можете использовать метод ReportProgress для возврата любого целого числа, например количества обработанных записей. Это не обязательно должен быть процент. Затем в обработчике ProgressChanged вы можете обновить текстовое поле. Например.
int count = e.ProgressPercentage;
textBox1.Text = string.Format("{0} images processed.", count);
Если вы не хотите использовать фонового рабочего, вы можете вызвать Application.DoEvents () внутри своего цикла. Это даст возможность пользовательскому интерфейсу обновляться и реагировать на действия пользователя. Но будьте осторожны - это сильно замедлит вашу программу, поэтому вы можете вызывать ее только на каждой сотой итерации.
Вы на правильном пути с фоновым рабочим. Вот пример, который я собрал, чтобы показать вам, как это сделать. Создайте новое приложение windows с формой Form1. Добавьте к ней 4 элемента управления: label1, backgroundWorker1, button1 и button2. Затем используйте этот code-behind. Затем вы можете использовать пользовательское состояние ReportProgress, чтобы сообщать главному потоку все, что захотите. В этом примере я передаю строку. Обработчик события ProgressChanged затем находится в потоке UI и обновляет текстовое поле.
public partial class Form1 : Form
{
int backgroundInt;
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.UserState as string;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundInt = 1;
while (backgroundWorker1.CancellationPending == false)
{
System.Threading.Thread.Sleep(500);
backgroundWorker1.ReportProgress(0,
String.Format("I found file # {0}!", backgroundInt));
backgroundInt++;
}
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
}
Пользовательский интерфейс не обновляется, потому что вы не разрешаете обрабатывать какие-либо оконные сообщения в длительном цикле обработки файлов. Приложения WinForms перерисовываются в ответ на сообщения WM_PAINT, которые обрабатываются в очереди сообщений в основном потоке.
Простейшее решение - принудительное обновление пользовательского интерфейса: попробуйте вызвать Update () в форме после изменения текстового поля внутри цикла.
Пользовательский интерфейс вашего приложения по-прежнему будет зависать (не реагировать на щелчки мыши и т. Д.), Но это должно, по крайней мере, отображать сообщения о ходе выполнения на экране. Если обновление дисплея - это все, что вам действительно нужно, остановитесь здесь.
Следующий уровень решения - позволить вашему приложению обрабатывать ожидающие оконные сообщения в вашем цикле обработки файлов. Вызовите Application.DoEvents () в своем цикле (вместо form.Update). Это позволит форме перерисовываться вместе с обновлениями вывода текста и устранит зависание пользовательского интерфейса - приложение может реагировать на действия мыши и клавиатуры.
Однако будьте осторожны - пользователь может щелкнуть кнопку, которая запустила текущее действие, в то время как текущее действие выполняется - повторный вход. Вы должны как минимум отключить меню или кнопку, которая запускает длительную обработку файла, чтобы предотвратить повторный вход.
Третий уровень решения - использовать фоновый поток для обработки файла. Это приводит к появлению целого ряда новых проблем, о которых вам необходимо знать, и во многих случаях потоков оказывается излишним. Нет особого смысла переносить обработку файла в фоновый поток, если вы не собираетесь позволять пользователю делать что-либо еще с вашим приложением во время обработки файла.
Просто создайте (1) делегат, чтобы обернуть вызов метода ProcessImages, (2) запустите вызов с помощью делегата, и (3) когда вы захотите обновить textbox из метода ProcessImages, проверьте работу перекрестного потока и убедитесь, что вы делаете обновление из главного потока:
delegate void ProcessImagesDelegate(string did, string sourceFolder, string destFolder, string strNumImages);
private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages)
{
// do work
// update textbox in form
if (this.textBox1.InvokeRequired)
{
this.textBox1.Invoke(new MethodInvoker(delegate() { this.textBox1.Text = "delegate update"; }));
}
else
{
this.textBox1.Text = "regular update";
}
// do some more work
}
public void MyMethod()
{
new ProcessImagesDelegate(ProcessImages).BeginInvoke(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString(), null, null);
}