【问题标题】:Pause the while loop until the button is pressed w/o using event handler C#暂停while循环,直到使用事件处理程序C#按下按钮
【发布时间】:2015-04-26 16:35:23
【问题描述】:

我正在努力锻炼如何创建一些基本上暂停我的 while 循环直到我按下 button1 的东西,我知道事件处理程序 button1_Click 但我认为这在这种情况下不会起作用,因为我有很多嵌套循环在我的 form_load 上互相访问。

任何帮助将不胜感激!

这是我的代码片段,我希望循环“暂停”并附上注释:

while (reader2.Read())
{
    QuestionSpace = Convert.ToString(reader2["Question Space"]);
    label1.Text = QuestionSpace;
    if (button1.Click = true) // if the button is clicked)
    {
        // continue with the while loop (I am going to add an INSERT SQL query in here later)
    }
    else
    {
        // pause until the button is pressed
    }
}  

我的整个表单代码:

public partial class CurrentlySetTestForm : Form
{
    private int QuestionID { get; set; }
    private string QuestionSpace { get; set; }
    public CurrentlySetTestForm()
    {
        InitializeComponent();
    }

    private void CurrentlySetTestForm_Load(object sender, EventArgs e)
    {
        string y = GlobalVariableClass.Signedinteacher;
        MessageBox.Show(y);
        Convert.ToInt32(y);

        string connectionString = ConfigurationManager.ConnectionStrings["myconnectionstring"].ConnectionString;
        SqlConnection connect = new SqlConnection(connectionString);

        connect.Open();

        SqlCommand command18 = new SqlCommand("SELECT [QuestionID] FROM QuestionStudentAssociation WHERE ( [StudentID]=@Signedinstudent)", connect);
        command18.Parameters.AddWithValue("@Signedinstudent", y);

        var reader = command18.ExecuteReader();

        while (reader.Read())
        {
            QuestionID = Convert.ToInt32(reader["QuestionID"]);

            SqlCommand command19 = new SqlCommand(@"SELECT [Question Space] FROM Questions WHERE ( [QuestionID] = @currentQID )", connect);
            command19.Parameters.AddWithValue("@currentQID", QuestionID);

            try
            {
                var reader2 = command19.ExecuteReader();

                while (reader2.Read())
                {
                    QuestionSpace = Convert.ToString(reader2["Question Space"]);
                    label1.Text = QuestionSpace;
                    if (button1.Click = true) // if the button is clicked)
                    {
                        // continue with the while loop (I am going to add an INSERT SQL query in here later)
                    }
                    else
                    {
                        // pause until the button is pressed
                    }


                }
            }
            catch (SyntaxErrorException ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                MessageBox.Show("Done one loop");
            }
        }
    }
}

【问题讨论】:

  • 如果您在 UI 线程中阻止执行,UI 将不会响应用户,因此她将无法单击按钮。您可以考虑将后台任务放在后台线程中,并使用使用 Tasks 的 AutoResetEvent。
  • 我不是 100% 确定你的意思
  • 如果要执行阻塞代码,则需要在UI线程以外的线程中执行。
  • 对不起,我不太了解 UI 线程是什么,您能否在答案中给我一个小例子?
  • 尝试阅读multi threading。要在不为线程问题困扰的情况下修复代码,请尝试编写代码以使用事件处理程序,而不是通过 while 循环的轮询机制。

标签: c# loops button while-loop nested-loops


【解决方案1】:

听起来你还没准备好学习 TPL

所以也许是 BackgroundWorker ,你可以在表单上绘制它

要使点击取消后台工作人员,请查看Cancel backgroundworker

我会花一些时间来学习 TPL,因为它会创建一个更简单、更优雅的解决方案。

至于暂停我会重构代码,你不应该让阅读器打开等待用户。

【讨论】:

    【解决方案2】:

    确实总是希望对 UI 事件做出事件驱动的响应。但是,我想您不想手动将逻辑拆分为状态机(每个事件都会触发进入下一个状态)。好吧,你很幸运,C# 编译器有一些关键字可以自动构建状态机,所以你不必管理细节。

    在 C# 中实现的连续传递样式实际上有两种不同的机制。如果您的 UI 事件几乎可以互换(或者您只对其中一个事件感兴趣),那么旧的 yield return 非常有用。像这样工作:

    IEnumerator<int> Coroutine;
    
    // this could be a Form_Load, but don't you need to get the user information before making the database connection?
    void BeginQuiz_Click( object sender, EventArgs unused )
    {
        Coroutine = RunQA();
    }
    
    IEnumerator<int> RunQA()
    {
         // connect to DB
    
         // show first question on UI
    
         return ContinueQA();
    }
    
    IEnumerator<int> ContinueQA()
    {
         // you can use a while loop instead if you really want
         for( int question = 0; question < questionCount; ++question )
         {
             // check answer
             if (/* too many wrong answers*/) {
                   // report failure in DB
                   yield break;
             }
    
             // get next question from DB
    
             // show new question on the UI
    
             // wait for UI action
             yield return question;
         }
    
         // report score in DB
          // update UI with completion certificate
    }
    
    void AnswerButton_Click( object sender, EventArgs unused )
    {
        answer = sender;
        Coroutine.MoveNext(); // MAGIC HAPPENS HERE
    }
    
    void TimeoutTimer_Tick( object sender, EventArgs unused )
    {
        answer = TimeoutTimer;
        Coroutine.MoveNext();
    }
    

    魔法来自yield return。每次函数到达yield return 时,编译器都会保存您正在执行的操作。当按钮单击事件发生并调用MoveNext 时,编译器会生成代码,该代码从yield return 暂停所有内容的位置开始,并从那里继续直到下一个yield return

    重要提示,ContinueQA 中的代码不会在 RunQA() 执行 return ContinueQA(); 时开始,它实际上从第一个 MoveNext() 开始。因此,相应地在RunQA()ContinueQA 之间拆分您的代码。

    如果您在代码的不同位置需要不同的暂停原因,那么async/await 会更有帮助。

    【讨论】:

      【解决方案3】:

      处理此问题的更好方法是使用计时器。这将允许表单绘制它的控件并处理所有输入,例如单击按钮。 根据您的需要调整计时器间隔(毫秒)。

      正如 Mehrzad Chehraz 所说,另一种方法是使用多线程。

      附带说明,如果可能,我强烈建议条件检查而不是 try/catch 检查。

      使用按钮启用/禁用计时器,并在计时器滴答时调用循环。 示例:

          Timer loopTimer = new Timer();
      
          private void Form1_Load(object sender, EventArgs e)
          {
              loopTimer.Interval = 100;
              loopTimer.Tick += loopTimer_Tick;
              loopTimer.Enabled = true;
          }
      
          void loopTimer_Tick(object sender, EventArgs e)
          {
              //perform the loop here at the set interval
          }
      
          private void button1_Click(object sender, EventArgs e)
          {
              //pause/play the loop
              loopTimer.Enabled = !loopTimer.Enabled;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-25
        • 2021-05-26
        • 2017-07-03
        • 1970-01-01
        • 1970-01-01
        • 2012-11-27
        • 2022-01-06
        • 1970-01-01
        相关资源
        最近更新 更多