我有一个包含多个循环和数据库查询的函数,我想通过传递一个进度条来异步调用它来向用户显示进度。
当我调用线程程序挂起时,我甚至无法关闭
当我调用synchContext.Post(state => etlBusiness.LoadData(progressBar),null);它冻结了,将loadData的逻辑带到UI是不可行的,有很多方法被称为内部
public partial class Home : Form
{
public Home()
{
InitializeComponent();
synchronizationContext = System.Threading.SynchronizationContext.Current;
}
private SynchronizationContext synchronizationContext;
public SynchronizationContext context = SynchronizationContext.Current;
public Thread _myThread = null;
private void btnSend_Click(object sender, EventArgs e)
{
_myThread = new Thread(() => LoadData(synchronizationContext, progressBar1));
_myThread.Start();
}
private void LoadData(System.Threading.SynchronizationContext synchContext, ProgressBar progressBar)
{
string filePath = tbPath.Text;
ETLBusiness etlBusiness = new ETLBusiness(filePath);
synchContext.Post(state => etlBusiness.LoadData(progressBar), null);
_myThread.Abort();
}
}
答案 0 :(得分:0)
您不需要使用Thread.Abort()
,SynchronizationContext
甚至使用"异步"代码(我假设您指的是await
/ async
,除非您的目标API实际上提供了真正的异步功能,否则您无法调用它,请注意使用Task.Run
并不是一回事) :WinForms具有内置功能,可在Invoke
/ BeginInvoke
方法的UI线程中运行代码。
对于进度报告,我建议不要传递ProgressBar
这样的设计,这意味着您的内部业务逻辑依赖于WinForms,这会阻止您在WPF,ASP.NET或无头进程;相反,您可以使用私有方法通过回调更新UI,如下所示:
private ProgressBar progressBar;
public Home()
{
this.InitializeComponent();
}
private void btnSend_Click( Object sender, EventArgs e )
{
Task.Run( (Action)this.LoadData )
}
private void UpdateProgress( Float progress )
{
if( this.InvokeRequired )
{
this.BeginInvoke( (Action<Float>)this.UpdateProgress, progress );
return;
}
this.progressBar.Value = progress * this.progressBar.Maximum;
}
private void LoadData()
{
ETLBusiness etlBusiness = new ETLBusiness(filePath);
etlBusiness.LoadData( this.UpdateProgress ); // You'll need to replace its progressBar parameter with a callback to `this.UpdateProgress`.
}
您的ETLBusiness.LoadData
方法应更改为:
void LoadData( Action<Float> progressCallback );
答案 1 :(得分:-1)
再次抱歉,此问题来自我之前发布的解决方案