Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 暂停while循环,直到在不使用事件处理程序C的情况下按下按钮#_C#_Loops_Button_While Loop_Nested Loops - Fatal编程技术网

C# 暂停while循环,直到在不使用事件处理程序C的情况下按下按钮#

C# 暂停while循环,直到在不使用事件处理程序C的情况下按下按钮#,c#,loops,button,while-loop,nested-loops,C#,Loops,Button,While Loop,Nested Loops,我正在努力学习如何创建一些基本上会暂停while循环直到按下按钮1的东西,我知道事件处理程序button1\u Click,但我认为这在这种情况下不起作用,因为我的表单加载中有很多循环嵌套在一起 任何帮助都将不胜感激 这是我的代码片段,我希望循环被“暂停”,并带有注释: while (reader2.Read()) { QuestionSpace = Convert.ToString(reader2["Question Space"]); label1.Text = Questi

我正在努力学习如何创建一些基本上会暂停while循环直到按下按钮1的东西,我知道事件处理程序button1\u Click,但我认为这在这种情况下不起作用,因为我的表单加载中有很多循环嵌套在一起

任何帮助都将不胜感激

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

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");
            }
        }
    }
}

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

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

另一方面,如果可能的话,我强烈建议进行条件检查,而不是尝试/捕获检查

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


听起来你还没有准备好学习第三方语言

所以你可以找个背景工作人员,把它画在表格上

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

我想花些时间学习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();
}
IEnumerator协同程序;
//这可能是一个表单加载,但是在建立数据库连接之前不需要获取用户信息吗?
void beginquirez_单击(对象发送方,事件参数未使用)
{
Coroutine=RunQA();
}
IEnumerator RunQA()
{
//连接到数据库
//在UI上显示第一个问题
返回ContinueQA();
}
IEnumerator ContinueQA()
{
//如果您真的需要,可以使用while循环
for(int-question=0;question
魔法来自于
收益回报率
。每次函数到达
产生返回
,编译器都会保存您正在执行的操作。当按钮单击事件出现并调用
MoveNext
时,编译器生成的代码从
yield return
暂停所有操作的地方开始,并从那里一直运行到下一个
yield return

重要注意事项,
ContinueQA
中的代码在
RunQA()
返回ContinueQA()时不会启动
它实际上从第一个
MoveNext()
开始。因此,将您的代码分为
RunQA()
ContinueQA


如果在代码的不同位置需要不同的暂停原因,则
async
/
wait
将更有帮助。

如果在UI线程中阻止执行,UI将不会响应用户,因此用户将无法单击按钮。您可以考虑将后台任务放在后台线程中,并使用使用任务的AutoReTebug。如果您想执行阻塞代码,我不确定100%是什么意思。你需要在UI线程以外的线程中执行。很抱歉,我不太理解UI线程是什么。你能在回答中给我一个小例子吗?试着阅读。要修复代码而不受线程问题的困扰,请尝试编写代码以使用事件处理程序,而不是while循环的轮询机制。
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();
}