当我使用消息框跟踪程序停止的位置时
在com.CommandText
它没有显示任何内容,应用程序挂起(冻结)。
如果我在没有Thread
的情况下使用它,那么相同的功能可以正常工作。
这是什么原因?
public bool load_complete=false;
private void button7_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(new ThreadStart(load_data));
t1.Start();
Thread.Sleep(2000);
while (load_complete == false) ;
t1.Abort();
}
// load_data()函数
public void load_data()
{
string connectionString = @"Data Source=(LocalDB)\v11.0;AttachDbFilename=" + Application.StartupPath + "\\Database1.mdf;Integrated Security=True;";
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
MessageBox.Show("open");
SqlCommand com = new SqlCommand();
try
{
com.Connection = conn;
DataSet ds = new DataSet();
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter();
com.CommandText = "select username,password from login where username ='" + textBox1.Text + "'";
da.SelectCommand = com;
da.Fill(dt);
dataGridView1.DataSource = dt;
username = (string)this.dataGridView1.Rows[0].Cells[0].Value;
pass = (string)this.dataGridView1.Rows[0].Cells[1].Value;
load_complete = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
答案 0 :(得分:3)
简短版本:您正在阻止UI线程,它将处理您的消息框的显示,不会阻止UI线程
更长的版本:
上面列出的代码存在许多问题。 让我们从明显的开始:
1
public bool load_complete=false;
...
while (load_complete == false) ;
您的flag
未标记为volatile,并且编译器优化可能会假定单个线程访问,在这种情况下,您的代码将永远停留在UI中。如果不是代码中的许多其他问题,我建议在这里使用volatile ...
2
Thread.Sleep(2000);
您正在阻止UI线程,因此任何用户交互超过2秒,这是CS101及其后的一大禁忌,请考虑使用Tasks和async / await来保持UI不可中断。对代码仍然使用SqlDataAdapter的最小更改需要:
a)标记按钮处理程序异步并等待您需要的任何内容:
private async void button7_Click(object sender, EventArgs e)
{
await load_data();
// more UI code is free to go here
}
b)在线程池上异步运行load_data
并将Task对象返回给调用者:
public Task load_data()
{
return Task.Run( () =>
{
// paste your old load_data code here verbatim
});
}
3
t1.Abort();
无法想象那个线程对你做了什么,所以你想要冷血打断它。当线程到达你传入的函数的末尾时,它会终止,绝对不需要在这里进行手动中止,如果你下次需要等待一个线程,请考虑Join方法
答案 1 :(得分:1)
另一种选择是使用BackgroundWorker,正如它所说,它使用的后台线程不会占用你的主UI线程。它已经包含了流程完成时的事件。
您只需将BackgroundWorker从“工具箱”拖动到表单即可。
注意:在LoadData方法中,您无法访问任何表单元素,因此您必须将MessageBox取出。您可以在BackgroundWorker完成的事件处理程序中引用表单元素。
private void button7_Click(object sender, EventArgs e)
{
MyWorker.RunWorkerAsync();
}
private void MyWorker_DoWork(object sender, DoWorkEventArgs e)
{
LoadData();
}
private void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
string username = (string)this.dataGridView1.Rows[0].Cells[0].Value;
string pass = (string)this.dataGridView1.Rows[0].Cells[1].Value;
}
else
{
MessageBox.Show("Houston we have a problem");
}
}
private void LoadData()
{
// Load your datagridview
}