2015-04-26 3 views
0

Я пытаюсь тренироваться, как создать что-то, что существенно приостанавливает мой цикл while до тех пор, пока не будет нажата кнопка button1, я знаю о обработчике события button1_Click, но я не знаю Думаю, что это сработает в этой ситуации, поскольку у меня много циклов, вложенных друг в друга в моей form_load.Приостановить цикл while до тех пор, пока кнопка не будет нажата без использования обработчика событий C#

Любая помощь была бы высоко оценена!

Это является отрезал мой код, где я хочу цикл, чтобы быть «приостановлено» с примечаниями:

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][email protected])", 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"); 
      } 
     } 
    } 
} 
+4

Если вы заблокируете выполнение в потоке пользовательского интерфейса, пользовательский интерфейс не будет отвечать на пользователя, поэтому она не сможет нажать кнопку. Вы могли бы рассмотреть задачу фоновой задачи в фоновом потоке и использовать AutoResetEvent для использования Заданий. –

+0

Я не уверен на 100%, что вы подразумеваете под этим – mot375

+0

Если вы хотите выполнить блокирующий код, вам нужно выполнить это в потоке, отличном от потока пользовательского интерфейса. –

ответ

0

Лучшим путем к это будет использование таймера. Это позволит форме рисовать элементы управления и обрабатывать все входные данные, например, щелкая по кнопке. Отрегулируйте интервал таймера (мс) в соответствии с вашими потребностями.

Другой способ сделать это будет, как сказал Мехрзад Чехраз, использовать многопоточность.

На стороне примечания, я бы настоятельно рекомендовал проверку условий проверки 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; 
    } 
1

Похоже, вы не готовы учиться TPL

Так, может быть, BackgroundWorker, вы можете нарисовать его на форме

Чтобы сделать щелчок отменить фона рабочего взглянуть на Cancel backgroundworker

Я бы хотел узнать, как TPL будет создавать более простое и элегантное решение.

Что касается паузы, я бы реорганизовал код, вы не должны держать читателя открытым, ожидая пользователя.

1

Вы: do хотите, чтобы события, связанные с событиями, всегда реагировали на события пользовательского интерфейса. Однако я полагаю, что вы не хотите разделить свою логику на конечный автомат вручную (где каждое событие запускает переход к следующему состоянию). Ну, вам повезло, у компилятора C# есть несколько ключевых слов для автоматического создания государственных машин, поэтому вам не нужно управлять деталями.

На самом деле существуют два разных механизма для стиля продолжения, реализованного на C#. Старый, 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.