C#在Windows窗体上的线程
C#在Windows窗体上的线程
这个问题已经有答案了:
可能是重复的问题:
我目前有一个C#程序来运行查询并在datagridview
中显示结果。
由于记录的大小,查询需要一段时间(20-30秒)才能运行。
我想添加一个动画,以便用户至少知道软件正在运行而不是停止工作。
当然,当调用过程时,我什么也不能运行,所以我研究了线程。
这是我的代码(请原谅我还没有写注释):
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.Sql; using System.Data.SqlClient; using System.Threading; namespace RepSalesNetAnalysis { public partial class Form1 : Form { public Form1() { InitializeComponent(); pictureBox2.Visible = false; } private void button1_Click(object sender, EventArgs e) { GetsalesFigures(); } private void Form1_Load(object sender, EventArgs e) { AutofillAccounts(); } private void GetsalesFigures() { try { string myConn = "Server=herp;" + "Database=shaftdata;" + "uid=fake;" + "pwd=faker;" + "Connect Timeout=120;"; string acct;// test using 1560 SqlConnection conn = new SqlConnection(myConn); SqlCommand Pareto = new SqlCommand(); BindingSource bindme = new BindingSource(); SqlDataAdapter adapt1 = new SqlDataAdapter(Pareto); DataSet dataSet1 = new DataSet(); DataTable table1 = new DataTable(); Thread aniSql = new Thread(new ThreadStart(animateIcon));//CREATE THE THREAD acct = accCollection.Text; string fromDate = this.dateTimePicker1.Value.ToString("MM/dd/yyyy"); string tooDate = this.dateTimePicker2.Value.ToString("MM/dd/yyyy"); Pareto.Connection = conn; Pareto.CommandType = CommandType.StoredProcedure; Pareto.CommandText = "dbo.GetSalesParetotemp"; Pareto.CommandTimeout = 120; Pareto.Parameters.AddWithValue("@acct", acct); Pareto.Parameters.AddWithValue("@from", fromDate); Pareto.Parameters.AddWithValue("@too", tooDate); aniSql.Start(); //START THE THREAD! adapt1.Fill(dataSet1, "Pareto"); aniSql.Abort(); //KILL THE THREAD! //pictureBox2.Visible = false; this.dataGridView1.AutoGenerateColumns = true; this.dataGridView1.DataSource = dataSet1; this.dataGridView1.DataMember = "Pareto"; dataGridView1.AutoResizeColumns( DataGridViewAutoSizeColumnsMode.AllCells); } catch (Exception execc) { MessageBox.Show("Whoops! Seems we couldnt connect to the server!" + " information:\n\n" + execc.Message + execc.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); } } private void AutofillAccounts() { //get customers list and fill combo box on form load. try { string myConn1 = "Server=derp;" + "Database=AutoPart;" + "uid=fake;" + "pwd=faker;" + "Connect Timeout=6000;"; SqlConnection conn1 = new SqlConnection(myConn1); conn1.Open(); SqlCommand accountFill = new SqlCommand("SELECT keycode FROM dbo.Customer", conn1); SqlDataReader readacc = accountFill.ExecuteReader(); while (readacc.Read()) { this.accCollection.Items.Add(readacc.GetString(0).ToString()); } conn1.Close(); } catch(Exception exc1) { MessageBox.Show("Whoops! Seems we couldnt connect to the server!" + " information:\n\n" + exc1.Message + exc1.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); } } public void animateIcon() { // animate pictureBox2.Visible = true; } } }
如您所见,我想在调用过程之前运行动画,然后在调用之后结束它。
我的线程知识是全新的。我找了一些资料,但现在感到有点困惑。
这是我的错误:
引发了“Cross-thread operation not valid: Control \'Form1\' accessed from a thread other than the thread it was created on.”(System.InvalidOperationException)的异常消息=“Cross-thread operation not valid: Control \'Form1\' accessed from a thread other than the thread it was created on.”,异常类型=“System.InvalidOperationException”
我需要一种非常简单的方法来执行一个动画,同时我的SQL pro在读取。
像picture.visible = true
这样的内容在开始时为真,结束时为假。
正如其他人指出的那样,您不能在单独的线程上执行与UI相关的操作。
如果您希望您的应用程序具有响应性,应该将数据操作放在单独的线程上执行。
如果您只想显示PictureBox控件,则根本不需要额外的线程:
pictureBox2.Visible = true; pictureBox2.Refresh(); // <-- causes the control to be drawn immediately ...large operation... pictureBox2.Visible = false;
然而,如果用户例如在您的应用程序中反复使用alt-tabs,或将另一个窗口拖到你的窗口上,由于UI线程正在执行数据操作,应用程序将似乎无响应。
令人吃惊的是,有这么多人建议您保留当前代码并使用InvokeRequired
和Invoke
,尽管Invoke
只会在UI线程有时间来处理它(在数据操作之后)时才会执行。
如果你想做这个,就需要调用Invoke。
private delegate void InvokeDelegate(); public void DoSomething() { if (InvokeRequired) { Invoke(new InvokeDelegate(DoSomething)); return; } // dosomething }
你也可以向代理添加变量并使用它们:
private delegate void InvokeDelegate(string text); public void DoSomething(string text) { if (InvokeRequired) { Invoke(new InvokeDelegate(DoSomething), text); return; } // dosomething with text }
希望这可以帮到你:).
斯蒂芬