我使用GridControl
填充BackgroundWorker
。然后我使用另一个BackgroundWorker
对数据集执行一些计算,数据集是GridControl
的数据源。在我尝试这样做时,会抛出GridControl
错误的交叉线程操作。我无法理解尽管没有对gridcontrol本身的任何操作执行错误的产生。 (我正在使用DevExpress,但这不应该改变这个概念。)
还有什么方法可以使用BackgroundWorker
来完成不同的工作,即使这段代码更有效率。
这是我的代码: -
public partial class MainForm : XtraForm
{
private BackgroundWorker loadworker = new BackgroundWorker();
private BackgroundWorker calcworker = new BackgroundWorker();
private AutoResetEvent resetEvent = new AutoResetEvent(false);
private Database _db = EnterpriseLibraryContainer.Current.GetInstance<Database>("ConnString");
private DataSet ds;
public MainForm()
{
InitializeComponent();
loadworker.DoWork += loadworker_DoWork;
loadworker.RunWorkerCompleted += loadworker_RunWorkerCompleted;
loadworker.ProgressChanged += loadworker_ProgressChanged;
loadworker.WorkerReportsProgress = true;
calcworker.DoWork += calcworker_DoWork;
calcworker.RunWorkerCompleted += calcworker_RunWorkerCompleted;
calcworker.ProgressChanged += calcworker_ProgressChanged;
calcworker.WorkerReportsProgress = true;
}
private void calcworker_DoWork(object sender, DoWorkEventArgs e)
{
int _cnt = 0;
foreach (DataRow dr in ds.Tables[0].Rows)
{
dr["GROSS"] = (decimal)dr["BASIC"] + (decimal)dr["HRA"] + (decimal)dr["DA"];
_cnt += 1;
}
for (int i = 0; i <= _cnt; i++)
{
Thread.Sleep(100);
calcworker.ReportProgress((100 * i) / _cnt);
}
}
private void calcworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.SetState(true);
this.MainInit();
}
private void calcworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.pgb_DataProgress.Position = e.ProgressPercentage;
}
private void loadworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.pgb_DataProgress.Position = e.ProgressPercentage;
}
private void loadworker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
DbCommand _cmd = _db.GetSqlStringCommand("SELECT Z.EMP_CODE,Z.BASIC,Z.DA,Z.HRA,CAST(0 AS DECIMAL) GROSS FROM Z000000001 Z");
DataSet _data = _db.ExecuteDataSet(_cmd);
for (int i = 0; i <= 10; i++)
{
Thread.Sleep(500);
loadworker.ReportProgress((100 * i) / 10);
}
e.Result = _data;
}
catch (Exception ex)
{
e.Cancel = true;
}
}
private void loadworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.ds = (DataSet)e.Result;
this.gridControl1.DataSource = ds.Tables[0];
this.SetState(true);
this.MainInit();
}
private void btn_FetchData_Click(object sender, EventArgs e)
{
this.gridControl1.DataSource = null;
this.SetState(false);
loadworker.RunWorkerAsync();
}
private void SetState(bool _state)
{
this.btn_Calculate.Enabled = _state;
this.btn_ClearGrid.Enabled = _state;
this.btn_FetchData.Enabled = _state;
}
private void MainInit()
{
this.pgb_DataProgress.Position = 0;
}
private void btn_ClearGrid_Click(object sender, EventArgs e)
{
this.gridControl1.DataSource = null;
}
private void btn_Calculate_Click(object sender, EventArgs e)
{
if (this.gridControl1.DataSource == null)
{
DevExpress.XtraEditors.XtraMessageBox.Show("Data Not loaded", "Message");
return;
}
else
{
this.SetState(false);
calcworker.RunWorkerAsync();
}
}
}
答案 0 :(得分:1)
将表作为DataSource附加后,它属于GUI。假设您的用户在Calc线程运行时更改/删除一行。各种各样的竞争条件都可能发生。
答案 1 :(得分:0)
简而言之,您无法访问创建它们的UI线程以外的线程上的控件。因此,任何控制方法/属性调用都必须使用Control.Invoke方法在UI线程上进行编组。
例如,在您的情况下,将在工作线程上调用loadworker_RunWorkerCompleted
事件处理程序,并且访问控件属性将引发错误。您需要将事件处理程序修改为
private void loadworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
System.Action a = () => {
this.ds = (DataSet)e.Result;
this.gridControl1.DataSource = ds.Tables[0];
this.SetState(true);
this.MainInit();
};
this.gridControl1.Invoke(a);
}