繁体   English   中英

暂停while循环,直到使用事件处理程序C#完全按下按钮为止

[英]Pause the while loop until the button is pressed w/o using event handler C#

我正在努力锻炼如何创建基本上可以暂停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");
            }
        }
    }
}

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

因此,也许BackgroundWorker可以将其绘制在窗体上

要使单击取消,后台工作人员可以查看“ 取消后台工作人员”

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

至于暂停,我将重构代码,您不应该让阅读器一直在等待用户。

确实总是希望事件驱动对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为止。

重要说明,当RunQA() return ContinueQA();时, ContinueQA中的代码不会启动return ContinueQA(); 它实际上从第一个MoveNext() 因此,请在RunQA()ContinueQA之间RunQA()拆分代码。

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

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

正如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;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM