模态对话框会阻止代码,直到返回为止。没有新窗口,我想要同样的事情。
一个带有单独对话框的简单示例(不我正在寻找的内容)
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();
}
是的,我知道这会失败,因为它会阻止整个线程。但这就是我正在寻找的那种系统,只是没有阻止线程,只有代码。这可能吗?
(我不是在寻找一种解决方法( - “在事件的事件处理程序中调用其余的代码。”)。我在问它是否可以按照描述完成。)
编辑:目标是使用Panel
(Dock = DockStyle.Fill
)替换我当前拥有的模态对话框。
答案 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();
}