[英]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.