я создал форму1 с кнопкой1, чтобы запустить задачу, которая будет обрабатываться на фоне с помощью BackGroundWorker в отдельном классе и отображать ProgressBar в отдельном окне.
моя проблема заключается в том, что процесс отлично работает, за исключением того, что задача выполнена, но прогрессная форма висит посередине.
ниже приведен класс BackGroundLoading
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.ComponentModel;
namespace sample2
{
public class BackgroundLoading
{
public BackgroundWorker Bw;
public delegate void RunFunction();
public RunFunction thisFunction;
mycontrols.LoadProgress p = new mycontrols.LoadProgress();
public BackgroundLoading(RunFunction newFunction)
{
thisFunction = newFunction;
Bw = new BackgroundWorker();
Bw.WorkerReportsProgress = true;
Bw.DoWork += new DoWorkEventHandler(Bw_DoWork);
Bw.ProgressChanged += new ProgressChangedEventHandler(Bw_ProgressChanged);
Bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bw_RunWorkerCompleted);
}
public void Start()
{
Bw.RunWorkerAsync();
}
void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Error: " + e.Error.Message);
}
if (e.Cancelled)
{
MessageBox.Show("Cancelled!");
}
else
{
MessageBox.Show("Completed!");
p.Close();
}
}
public void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
/// If I put
/// p.ProgBar.Value = e.ProgressPercentage;
/// the progressbar hangs upon form show.
}
void Bw_DoWork(object sender, DoWorkEventArgs e)
{
p.Show();
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 100); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (thisFunction != null)
{
thisFunction();
worker.ReportProgress((i * 1));
p.ProgBar.Value = i;
}
else
{
MessageBox.Show("Error, no method found");
}
}
}
}
}
}
это код Form1.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace sample2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
BackgroundLoading BL = new BackgroundLoading(workingmethod);
BL.Start();
}
private void workingmethod()
{
System.Threading.Thread.Sleep(10);
}
}
}
это код для формы LoadProgress
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace sample2.mycontrols
{
public partial class LoadProgress : Form
{
public LoadProgress()
{
InitializeComponent();
}
private void LoadProgress_Load(object sender, EventArgs e)
{
}
}
}
нет кода в форме progressbar, так как обновление выполняется в классе. не может найти причину зависания.
Заранее спасибо.
Покажите форму в главном потоке пользовательского интерфейса, непосредственно перед запуском BackgroundWorker
:
public void Start()
{
p.Show();
Bw.RunWorkerAsync();
}
Затем вы можете совершать вызовы в форме в событии ProgressChanged
, которое выполняется в потоке пользовательского интерфейса.
Удалите p.Show()
и p.ProgBar.Value = i;
из события DoWork
- вы не хотите касаться нити пользовательского интерфейса из фонового потока.
public void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
p.ProgBar.Value = e.ProgressPercentage;
}
Наконец, закройте форму, когда BackgroundWorker
будет завершен (что вы уже делаете):
void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
p.Close();
}
p.Show();
из обработчика событийBw_DoWork
(вероятнее всего, будет работать ctor BackgroundLoading)? Элементы управления WinForms не должны быть доступны из фоновых потоков (DoWork запускается не из пользовательского интерфейса, фоновый поток). Доступ к свойствам Form или UserControl из любого потока, кроме потока пользовательского интерфейса, вызывает непредсказуемое поведение - то же самое относится и кp.ProgBar.Value = i;
(Вы можете обновить это в событии ProgressChanged, которое правильно маршалируется в поток пользовательского интерфейса)