C# 强制循环等待事件

C# 强制循环等待事件,c#,loops,event-handling,C#,Loops,Event Handling,我正在尝试编写一个方法,该方法遍历一个项目列表——对于每个项目,将其添加到表单中,然后等待用户输入一些数据并单击按钮。然而,我不知道我应该/可以用什么来创造这个 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. } 到目前为止,我只

我正在尝试编写一个方法,该方法遍历一个项目列表——对于每个项目,将其添加到表单中,然后等待用户输入一些数据并单击按钮。然而,我不知道我应该/可以用什么来创造这个

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
类,它似乎只适用于线程

如何实现这一点?

如果您也使用async/await,则可以使用信令实现这一点-例如,您可以等待通过单击按钮完成的任务-但一般来说,您应该以更为事件驱动的方式考虑用户界面

不要在此处使用
foreach
循环,而是在显示项目的集合中保留索引,并在每次单击按钮时将其前进。(当然,请记住检查是否有更多的项目要显示。)

如果您也使用async/await,则可以使用信令来完成此操作-例如,您可以等待通过单击按钮完成的任务-但一般来说,您应该以更为事件驱动的方式考虑用户界面


不要在此处使用
foreach
循环,而是在显示项目的集合中保留索引,并在每次单击按钮时将其前进。(当然,记得检查是否有更多的项目要显示。)

虽然我大体上同意Jon Skeet,但Mads Torgensen做了一个有趣的演示,演示了如何使用
异步/等待
来简化这些场景(使用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;
    }
}
样本测试将其全部放在一起:

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;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Threading.Tasks;
使用System.Windows.Forms;
名称空间示例
{
静态类测试
{
[状态线程]
静态void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form=new form();
var txtName=newtextbox{Parent=form,Top=8,Left=8};
var buttonNext=new按钮{Parent=form,Top=txtName.Bottom+8,Left=8,Text=“Next”};
form.Load+=异步(发送方,e)=>
{
var List=新列表{“A”、“B”、“C”、“D”};
foreach(列表中的字符串s)
{
txtName.Text=s;
单击时等待按钮下一步();
}
txtName.Text=“”;
buttonNext.Enabled=false;
};
申请表格;
}
}
公共静态类Utils
{
单击时的公共静态任务(此按钮)
{
var tcs=new TaskCompletionSource();
EventHandler onClick=null;
onClick=(发送方,e)=>
{
按钮。单击-=onClick;
tcs.TrySetResult(空);
};
按钮。单击+=onClick;
返回tcs.Task;
}
}
}

虽然我大体上同意Jon Skeet,但Mads Torgensen做了一个有趣的演示,演示了如何使用
异步/等待
简化此类场景(使用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;
    }
}
样本测试将其全部放在一起:

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;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Threading.Tasks;
使用System.Windows.Forms;
名称空间示例
{
静态类测试
{
[状态线程]
静态void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form=new form();
var txtName=newtextbox{Parent=form,Top=8,Left=8};
var buttonNext=new按钮{Parent=form,Top=txtName.Bottom+8,Left=8,Text=“Next”};
form.Load+=异步(发送方,e)=>
{
var List=新列表{“A”、“B”、“C”、“D”};
foreach(列表中的字符串s)
{
txtName.Text=s;
单击时等待按钮下一步();
}
txtName.Text=“”;
buttonNext.Enabled=false;
};
申请表格;
}
}
公共静态类Utils
{
单击时的公共静态任务(此按钮)
{
var tcs=new TaskCompletionSource();
EventHandler onClick=null;
onClick=(发送方,e)=>
{
按钮。单击-=onClick;
tcs.TrySetResult(空);
};
按钮。单击+=onClick;
返回tcs.Task;
}
}
}

在这一点上,我同意Jon Skeet的观点,试图迫使UI框架以一种不正常的方式工作,因为它通常会导致问题。即使它工作,你也会有其他人难以理解的代码,因为它会以一种不寻常的方式工作

Lisp中的一些web框架的工作方式使页面显示看起来像方法调用。我在.NET中没有看到任何这样的

我的第一个想法是你打电话申请