2015-09-29 4 views
1

Я пытаюсь написать метод, который проходит через список элементов - каждый добавляет его в форму, а затем ждет, когда пользователь введет некоторые данные и нажмите кнопку. Однако я не знаю, что я должен/мог использовать для создания этого.Силовой цикл для ожидания события

foreach (string s in List) 
{ 
    txtName.Text = s; 
    //wait for button click... 

    // When the user is ready, they click the button to continue the loop. 
} 

До сих пор все, что я нашел это EventWaitHandle класс, который, кажется, применяются только для потоков.

Как я могу это достичь?

ответ

3

это способы сделать это, используя сигнализацию, если вы также используете async/await - вы могли бы ожидать выполнения задачи, которая завершается нажатием кнопки, например, но в целом вы должны думать об пользовательских интерфейсах в более управляемый событиями путь.

Вместо того, чтобы иметь здесь петлю foreach, держите указатель в коллекции, для которой отображается элемент, и продвигайте его каждый раз, когда нажимается кнопка. (Не забудьте проверить ли есть или нет больше элементов для отображения, конечно.)

1

Хотя я согласен в целом с Jon тарелочкам, была интересная презентация Мадс Torgensen демонстрирует, как async/await может быть используется для упрощения таких сценариев (с использованием методов, упомянутых Jon). В конце концов, это не то же самое, что с перечисляющими - мы можем написать собственный класс перечислителя, используя состояние, подобное индексу и т. Д., Но мы почти никогда этого не делаем и вместо этого используем блоки итераторов.

Во всяком случае, это техника async/await, о которой мы говорили.

Во-первых, многоразовый часть:

public static class Utils 
{ 
    public static Task WhenClicked(this Button button) 
    { 
     var tcs = new TaskCompletionSource<object>(); 
     EventHandler onClick = null; 
     onClick = (sender, e) => 
     { 
      button.Click -= onClick; 
      tcs.TrySetResult(null); 
     }; 
     button.Click += onClick; 
     return tcs.Task; 
    } 
} 

и ваш код, используя его (обратите внимание, что вам нужно, чтобы отметить свой метод как async)

foreach (string s in List) 
{ 
    txtName.Text = s; 
    await yourButton.WhenClicked(); 
} 

испытание образца положить все это вместе:

using System; 
using System.Collections.Generic; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace Samples 
{ 
    static class Test 
    { 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      var form = new Form(); 
      var txtName = new TextBox { Parent = form, Top = 8, Left = 8 }; 
      var buttonNext = new Button { Parent = form, Top = txtName.Bottom + 8, Left = 8, Text = "Next" }; 
      form.Load += async (sender, e) => 
      { 
       var List = new List<string> { "A", "B", "C", "D " }; 
       foreach (string s in List) 
       { 
        txtName.Text = s; 
        await buttonNext.WhenClicked(); 
       } 
       txtName.Text = ""; 
       buttonNext.Enabled = false; 
      }; 
      Application.Run(form); 
     } 
    } 
    public static class Utils 
    { 
     public static Task WhenClicked(this Button button) 
     { 
      var tcs = new TaskCompletionSource<object>(); 
      EventHandler onClick = null; 
      onClick = (sender, e) => 
      { 
       button.Click -= onClick; 
       tcs.TrySetResult(null); 
      }; 
      button.Click += onClick; 
      return tcs.Task; 
     } 
    } 
} 
+0

Может быть состояние гонки, которое приводит к потерянным нажатием кнопки. Риск состоит в том, что есть щелчок между удалением события и добавлением нового события. Это будет зависеть от того, как имплантация ожидания взаимодействует с очередью сообщений Windows. –

+0

@IanRingrose Согласен. Но это может не быть проблемой для такой программы, как симуляция типа обработки консоли, например, задание вопроса и ожидание ответа. –

0

Я с Джоном Скитом на этом, пытаясь заставить структуру пользовательского интерфейса в способ работы, который не является нормальным для него, часто приводит к проблемам. Даже если это сработает, у вас будет код, который трудно понять кому-либо другому, поскольку он будет работать необычным способом.

Некоторые веб-фреймворки в Lisp работали таким образом, чтобы отображать страницы веб-страниц как вызовы методов. Я ничего не видел в .NET, который делает это.

Моя первая мысль заключается в том, чтобы вы могли вызвать Application.DoEvents() в цикле, проверяя флагов, что ваши обратные вызовы кнопок. Однако ваше приложение будет использовать 100% ожидающего процессора, пока оно ничего не делает. См. http://blog.codinghorror.com/is-doevents-evil/

Ваша заявка finite state machine, которая реагирует на события от пользователя и переходит в новое состояние всякий раз, когда требуется соответствующее событие, чтобы соответствовать переходу состояния из текущего состояния. За эти годы было много попыток моделировать это в коде, но я не видел ничего лучшего, чем просто использование стандартной обработки событий.

Смежные вопросы