我正在尝试编写一个遍历项目列表的方法 - 每个项目都将其添加到表单中,然后等待用户输入一些数据并单击按钮。但是我不知道我应该/可以使用什么来创建它。
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
类,它似乎只适用于线程。
我怎样才能做到这一点?
答案 0 :(得分:3)
如果您还使用async / await,那么是使用信号发送的方式 - 您可以等待按下被点击的按钮完成的任务 - 但一般情况下您应该认为关于用户界面的更多事件驱动方式。
不要在此处使用foreach
循环,而是将索引保存到正在显示项目的集合中,并在每次单击按钮时将其前进。 (当然,请记住检查是否要显示的项目。)
答案 1 :(得分:1)
虽然我一般同意 Jon Skeet ,但 Mads 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;
}
}
}
答案 2 :(得分:0)
我和Jon Skeet就这一点,试图强迫UI框架成为一种不正常的工作方式,这往往会导致问题。即使它有效,你也会拥有其他人难以理解的代码,因为它会以一种不寻常的方式工作。
Lisp中的一些Web框架的工作方式使页面网页显示看起来像方法调用。我没有在.NET中看到过这样做的任何内容。
我首先想到的是在循环中调用Application.DoEvents(),检查按钮回调设置的标志。但是,您的应用程序将使用100%的CPU等待而不执行任何操作。见http://blog.codinghorror.com/is-doevents-evil/
您的应用程序是finite state machine,它响应来自用户的事件,并在所需事件到达时与当前状态的状态转换匹配时进入新状态。多年来已经有很多尝试在代码中对此进行建模,我所看到的并没有出现任何比仅使用标准事件处理更好的东西。