Mad*_*sen 45 c# wpf multithreading backgroundworker winforms
我花了一整天的时间试图让我的应用程序使用线程,但没有运气.我已经阅读了很多关于它的文档,我仍然会遇到很多错误,所以我希望你能帮助我.
我有一个耗时的方法,它调用数据库并更新GUI.这必须一直发生(或大约每30秒).
public class UpdateController
{
private UserController _userController;
public UpdateController(LoginController loginController, UserController userController)
{
_userController = userController;
loginController.LoginEvent += Update;
}
public void Update()
{
BackgroundWorker backgroundWorker = new BackgroundWorker();
while(true)
{
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerAsync();
}
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
_userController.UpdateUsersOnMap();
}
}
Run Code Online (Sandbox Code Playgroud)
使用这种方法我得到一个例外,因为后台工作者不是和STA线程(但从我可以理解这是我应该使用的).我试过一个STA线程,并给出了其他错误.
我认为问题是因为我在进行数据库调用时尝试更新GUI(在后台线程中).我应该只进行数据库调用,然后以某种方式它应该切换回主线程.在主线程执行后,它应该返回后台线程,依此类推.但我看不出怎么做.
应用程序应在数据库调用后立即更新GUI.Firering事件似乎不起作用.背景线程只是输入它们.
编辑:
一些非常好的答案:)这是新的代码:
public class UpdateController{
private UserController _userController;
private BackgroundWorker _backgroundWorker;
public UpdateController(LoginController loginController, UserController userController)
{
_userController = userController;
loginController.LoginEvent += Update;
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.DoWork += backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}
public void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_userController.UpdateUsersOnMap();
}
public void Update()
{
_backgroundWorker.RunWorkerAsync();
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//UI update
System.Threading.Thread.Sleep(10000);
Update();
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Big database task
}
Run Code Online (Sandbox Code Playgroud)
}
但是我怎么能每隔10秒运行一次呢?System.Threading.Thread.Sleep(10000)将使我的GUI冻结,而Update()中的while(true)循环按建议给出异常(Thread太忙).
kiw*_*pom 46
您需要声明并配置BackgroundWorker一次 - 然后在循环中调用RunWorkerAsync方法...
public class UpdateController
{
private UserController _userController;
private BackgroundWorker _backgroundWorker;
public UpdateController(LoginController loginController, UserController userController)
{
_userController = userController;
loginController.LoginEvent += Update;
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
_backgroundWorker.WorkerReportsProgress= true;
}
public void Update()
{
_backgroundWorker.RunWorkerAsync();
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
// Do the long-duration work here, and optionally
// send the update back to the UI thread...
int p = 0;// set your progress if appropriate
object param = "something"; // use this to pass any additional parameter back to the UI
_backgroundWorker.ReportProgress(p, param);
}
}
// This event handler updates the UI
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update the UI here
// _userController.UpdateUsersOnMap();
}
}
Run Code Online (Sandbox Code Playgroud)
Mik*_*all 11
您必须使用Control.InvokeRequired属性来确定您是否在后台线程上.然后,您需要通过Control.Invoke方法调用修改UI的逻辑,以强制在主线程上进行UI操作.您可以通过创建委托并将其传递给Control.Invoke方法来完成此操作.这里的问题是你需要从Control派生的一些对象来调用这些方法.
编辑:当另一个用户发布时,如果您可以等到BackgroundWorker.Completed事件来更新您的UI,那么您可以订阅该事件并直接调用您的UI代码.在主应用程序线程上调用BackgroundWorker_Completed.我的代码假设您希望在操作期间进行更新.我的方法的一个替代方案是订阅BwackgroundWorker.ProgressChanged事件,但我相信在这种情况下你仍然需要调用Invoke来更新你的UI.
例如
public class UpdateController
{
private UserController _userController;
BackgroundWorker backgroundWorker = new BackgroundWorker();
public UpdateController(LoginController loginController, UserController userController)
{
_userController = userController;
loginController.LoginEvent += Update;
}
public void Update()
{
// The while loop was unecessary here
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerAsync();
}
public delegate void DoUIWorkHandler();
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// You must check here if your are executing on a background thread.
// UI operations are only allowed on the main application thread
if (someControlOnMyForm.InvokeRequired)
{
// This is how you force your logic to be called on the main
// application thread
someControlOnMyForm.Invoke(new
DoUIWorkHandler(_userController.UpdateUsersOnMap);
}
else
{
_userController.UpdateUsersOnMap()
}
}
}
Run Code Online (Sandbox Code Playgroud)