C#在Windows窗体上的线程

5 浏览
0 Comments

C#在Windows窗体上的线程

这个问题已经有答案了

可能是重复的问题:

如何在C#中从另一个线程更新GUI?

我目前有一个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这样的内容在开始时为真,结束时为假。

admin 更改状态以发布 2023年5月23日
0
0 Comments

正如其他人指出的那样,您不能在单独的线程上执行与UI相关的操作。

如果您希望您的应用程序具有响应性,应该将数据操作放在单独的线程上执行。

如果您只想显示PictureBox控件,则根本不需要额外的线程:

pictureBox2.Visible = true;
pictureBox2.Refresh(); // <-- causes the control to be drawn immediately
...large operation...
pictureBox2.Visible = false;

然而,如果用户例如在您的应用程序中反复使用alt-tabs,或将另一个窗口拖到你的窗口上,由于UI线程正在执行数据操作,应用程序将似乎无响应。

令人吃惊的是,有这么多人建议您保留当前代码并使用InvokeRequiredInvoke,尽管Invoke只会在UI线程有时间来处理它(在数据操作之后)时才会执行。

0
0 Comments

如果你想做这个,就需要调用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
      }

希望这可以帮到你:).

斯蒂芬

0