阻止代码直到事件触发(如模态对话框)

时间:2014-01-06 19:28:12

标签: c# .net winforms visual-studio-2010 .net-4.0

模态对话框会阻止代码,直到返回为止。没有新窗口,我想要同样的事情。

一个带有单独对话框的简单示例(我正在寻找的内容)

MessageBox.Show("Continue");
MessageBox.Show("This waits until the first returns.");

我正在寻找的一个简单的非工作示例:

mres1.Wait();//Where: ManualResetEventSlim mres1 = new ManualResetEventSlim(false); 
MessageBox.Show("This should wait until button2 is clicked.");

+

private void button2_Click(object sender, EventArgs e)
{
    mres1.Set();
}

是的,我知道这会失败,因为它会阻止整个线程。但这就是我正在寻找的那种系统,只是没有阻止线程,只有代码。这可能吗?

(我不是在寻找一种解决方法( - “在事件的事件处理程序中调用其余的代码。”)。我在问它是否可以按照描述完成。)

编辑:目标是使用PanelDock = DockStyle.Fill)替换我当前拥有的模态对话框。

4 个答案:

答案 0 :(得分:2)

这是SiLo's old solution的略微修改版本,它不使用任何额外的线程,仍然可以与.NET 4.0一起使用

编辑:已更新以使用面板,可能需​​要稍微调整一下,但我认为这样可以让你获得99%的成功。

private TaskCompletionSource<object> waiter = new TaskCompletionSource<object>(); 

private void button1_Click(object sender, EventArgs e)
{

    Panel coverScreen = new Panel();
    coverScreen.BackColor = Color.Black;
    coverScreen.Dock = DockStyle.Fill;
    this.Controls.Add(coverScreen);

    waiter.Task.ContinueWith(_ =>
    {
        this.Controls.Remove(coverScreen);
        coverScreen.Dispose();
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

private void button2_Click(object sender, EventArgs e)
{
    waiter.SetResult(null);
    waiter = new TaskCompletionSource<object>(); //Reset the TaskCompletionSource
}

答案 1 :(得分:1)

编辑:我想我更了解你的意图。基本上,您希望创建自己的模态行为,而不是使用系统默认行为。

在这种情况下,您需要两个单独的代码块一个接一个地运行,并等待一些用户交互来触发转换(例如OK按钮或Hide()方法)。

也许最好创建自己的ModalPanel UI元素,该元素将从基础Panel控件驱动。在您的子类中,您可以公开一个允许您放入任务的ShowModal方法,并在ModalPanel被隐藏后执行。

例如:

class ModalPanel : Panel
{
    protected readonly Button okButton;
    Task task;

    public ModalPanel()
    {
        okButton = new Button();

        okButton.Width = 100;
        okButton.Height = 32;

        okButton.Left = (this.Width - okButton.Width) / 2;
        okButton.Top = (this.Height - okButton.Height) / 2;

        okButton.Text = "OK";
        okButton.Click += delegate { this.Hide(); };
    }

    public virtual void ShowModal(Task completion)
    {
        this.task = completion;

        this.Dock = DockStyle.Fill;
        this.Show();
    }

    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);

        var isHidden = !this.Visible;

        if (isHidden && task != null)
            task.Start();
    }
}

答案 2 :(得分:0)

如果您想继续更新UI,那么您应该查看await / async方法,但是您可以通过这种方式在非UI线程上等待/发出信号:

如果您偏爱TPL,可以使用任务&lt;&gt;

ManualResetEventSlim mres1 = null;

private void button1_Click(object sender, EventArgs e)
{
   System.Threading.ThreadPool.QueueUserWorkItem( Wait , null );
}

private void Wait(object state)
{
    mres1 = new ManualResetEventSlim(false);
    mres1.Wait();
    //rest of the code to execute....
}
private void button2_Click(object sender, EventArgs e)
{
    mres1.Set();

}

答案 3 :(得分:-1)

await,结合将所需内容转换为任务的方法,使其既简单,清晰又有效。

private async void button1_Click(object sender, EventArgs e)
{
    var tcs = new TaskCompletionSource<bool>();
    button2.Click += (s, args) => tcs.TrySetResult(true);
    await tcs.Task;
    DoSomething();
}