【问题标题】:Why does windows form freeze when it loads in C#?为什么 windows 窗体在 C# 中加载时会冻结?
【发布时间】:2017-01-21 20:45:17
【问题描述】:

我是 C# 新手,我正在使用 windows forms。 我正在构建一个应用程序,当Form 加载时我遇到了一个奇怪的严重问题。

我有 2 个forms:

Form1 有一个 button_EditDataGridView

Form2 有一个DataGridView1DataGridView2

正如代码和屏幕截图所示,在Form1 中,当我在DataGridView 中选择一行时,然后单击Button_Edit Order numberDateTimeDataGridView 中的值@987654341 @ 被传递给Form2,然后Form2 打开。 现在在Form2Load event 中有一个SQL 查询,它需要Order numberDateTime 带来相关的订单详细信息,然后在Form2 中填写DataGridView1DataGridView2

  • 在表格 1 中:

    Form2 frm2 = new Form2();
    private void button_Edit_Click(object sender, EventArgs e) 
     {
    
         frm2._ Order_Number= Convert.ToInt32(dataGridView1.SelectedRows[0].Cells[0].Value);
         frm2._ Date_Time= Convert.ToDateTime(dataGridView1.SelectedRows[0].Cells[4].Value);
    
         frm2.ShowDialog();
    
     }
    
  • 在 Form2 中:

      SqlConnection MyConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
      SqlCommand MyCommand = new SqlCommand();
      DataTable DataTable = new DataTable();
      SqlDataAdapter Sql_Data_Adapter = new SqlDataAdapter();
    
    int Order_Number;
    DateTime Date_Time;
    int i;
    double Sum;
    int RowIndex;
    
     public int _ Order_Number
      {
    
          set { Order_Number = value; }
      }
    
    
      public DateTime _ Date_Time
      {
    
          set { Date_Time = value; }
      }
    
     private void Form2_Load(object sender, EventArgs e)
    
      {
    
    
                DataTable.Rows.Clear();
                DataTable.Columns.Clear();
    
                MyConnection.Open();
    
                MyCommand.CommandText = "SELECT * FROM Customer_Order_Details WHERE Order_Number = @OrderNumber and Date_Time = @DateTime ";
                MyCommand.Connection = MyConnection;
                MyCommand.Parameters.Add("@OrderNumber", SqlDbType.Int).Value = Order_Number;
                MyCommand.Parameters.Add("@DateTime", SqlDbType.DateTime).Value = Date_Time;
    
                Sql_Data_Adapter.SelectCommand = MyCommand;
                Sql_Data_Adapter.Fill(DataTable);
                MyCommand.Parameters.Clear();
                MyConnection.Close();
    
                dataGridView1.Rows.Clear();
                dataGridView2.Rows[0].Cells[1].Value = 0;
    
                Sum = 0;
    
                //////////////FILL THE ORDER INTO DATAGRIDVIEW1///////////
                 RowIndex = DataTable.Rows.Count - 1;
                for (i = 0; i <= RowIndex; i++)
                {
    
                    dataGridView1.Rows.Add(DataTable.Rows[i][2], DataTable.Rows[i][3], DataTable.Rows[i][4]);
    
                     // Calculate the total:
                    Sum = Convert.ToDouble(DataTable.Rows[i][4]) + Sum;                       
    
                }
    
                dataGridView2.Rows[0].Cells[1].Value = sum;
    
    
    }
    
  • 问题:

此代码运行良好,正如我所愿,Form2 中的 DataGridView1DataGridView2 填充了正确的细节,并且在 Form2 加载时运行良好。 但是,有时Form2Form2 加载时填充DataGridView1DataGridView2 后会冻结,并且我无法执行任何操作,直到我使用任务管理器终止应用程序。 这个问题有时会发生,而且是不可预测的。真不知道怎么回事。

我查看了 hereherehere 但这些问题与我的问题无关。请注意,我已经使用了 try catch 并且它不会抛出任何东西,因为表单会冻结。这种冻结行为发生在发布模式下,我的意思是在我构建 EXE 文件然后将其安装在 PC 中之后,问题就发生了。

有没有人知道为什么会发生这种不可预测的不良行为? 我的代码有什么需要改变的吗? 我很乐意听取任何新的想法/解决方案,无论它有多小,都会非常有益。 谢谢你

【问题讨论】:

  • 这意味着您的应用程序在您的代码中的某个时间点停止了。用 try catch 包围你的代码并打印堆栈跟踪
  • 您应该通过修复问题的异步方法填充 DataGridView 吗?
  • @Roljhon 。我已经使用了 try catch,它不会抛出任何东西,因为表单冻结了。
  • 您知道卡在哪里吗?还可以考虑使用using 进行连接。不再使用时应丢弃
  • @Serena 你的意思是即使视觉工作室都在冻结?您是否尝试过不从 Visual Studio 启动而单独运行应用程序?

标签: c# sql


【解决方案1】:

SQL 在另一个线程上工作。查看异步调用。

BeginInvoke

【讨论】:

  • 谢谢。我会试试这个。
【解决方案2】:

我建议使用Open(连接到RDBMS)和ExecuteReader(查询执行)的Async版本:

con.Open()        -> await con.OpenAsync()
q.ExecuteReader() -> await q.ExecuteReaderAsync()

这种简单的替换使 UI 负责任(它不会冻结)在连接到 RDBMS 并执行查询时。

// do not forget to mark Form2_Load method as async 
private async void Form2_Load(object sender, EventArgs e) {
  // Do not share the connection - create it and dispose for each call 
  using (SqlConnection con = new SqlConnection(...)) {
    await con.OpenAsync();

    string sql = 
      @"SELECT * 
          FROM Customer_Order_Details 
         WHERE Order_Number = @OrderNumber 
           AND Date_Time = @DateTime";

    // do not share command/query as well 
    using (SqlCommand q = new SqlCommand(sql, con)) {
      q.Parameters.Add("@OrderNumber", SqlDbType.Int).Value = Order_Number;
      q.Parameters.Add("@DateTime", SqlDbType.DateTime).Value = Date_Time;

      dataGridView1.Rows.Clear();
      dataGridView2.Rows[0].Cells[1].Value = 0;

      Sum = 0;

      // We actually don't want any sql adapter: 
      // all we have to do is to fetach data from cursor and append it to grids
      using (var reader = await q.ExecuteReaderAsync()) {
        while (reader.Read()) {
          dataGridView1.Rows.Add(reader[2], reader[3], reader[4]);
          Sum += Convert.ToDouble(reader[4]);  
        }
      } 
    }  
  }
}

【讨论】:

    【解决方案3】:

    如上所述,您给我们的代码 sn-p 写得不好。您应该使用更多的 Try/Catch 语句来防止程序崩溃和冻结。即使在发行版中运行程序时,这也将帮助您找到错误。此外,您有很多选择来解决您的问题。

    1: 尝试在第二个线程中启动 Form2,然后只有你的 form2 会冻结,直到你的 sql 完成

    2: 如前所述,尝试使用异步调用来避免处理 sql 的冻结时间

    3: 没有直接需要 SQL 数据库/连接。您还可以使用集合并创建由您的产品定义的对象(如可乐),然后它们通过数据库绑定它们。 (如果你有兴趣我可以给你举个例子)

    对你来说最好的方法是:

    添加一些 Try/Catch 语句并熟悉它,熟悉 Systems.Thread 并尝试在新线程中启动您的 form2,如果这不起作用转到步骤 2 并添加异步调用

    最后我想告诉你,将你的表单命名为“Form1”和“Form2”并不好,也许你想改变它。

    【讨论】:

    • 感谢您的建议。我可以在单独的线程中进行 sql 查询吗?
    猜你喜欢
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2019-12-21
    • 2011-04-02
    • 1970-01-01
    相关资源
    最近更新 更多