C# 暂停while循环,直到在不使用事件处理程序C的情况下按下按钮#
我正在努力学习如何创建一些基本上会暂停while循环直到按下按钮1的东西,我知道事件处理程序button1\u Click,但我认为这在这种情况下不起作用,因为我的表单加载中有很多循环嵌套在一起 任何帮助都将不胜感激 这是我的代码片段,我希望循环被“暂停”,并带有注释: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 (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();
}