我有一个类似MVP的应用程序,所有昂贵的操作都使用Async调用并显示一个像gif这样的Ajax,指示用户发生了某些事情,而没有阻塞主线程。
实施例: 数据输入表单,用户单击“保存”,发生异步操作,完成后将屏幕恢复为可编辑的形式,而不会阻止UI线程(换句话说,不会阻止应用程序中的其他可见窗口)。
在这里一切正常,但考虑到以下情况:
用户尝试关闭表单,并收到一条确认消息,询问用户是否确定如果他在关闭前更喜欢保存将关闭。 当用户单击“保存”时,之前解释的逻辑相同,但是我被迫等待此调用在UI线程中完成(如果异步调用中有任何错误或者其他什么)我不能找到任何方式在不阻止UI线程的情况下以其他方式执行。
有什么建议吗?谢谢!
---编辑---- 我现在正在做的是在这个循环中等待Presenter中的所有WaitHandles:
while (!WaitHandles.All(h => h.WaitOne(1)))
Application.DoEvents();
感觉有点脏..但至少它模拟非阻塞线程。这是出于某种原因我不应该做的事情吗?
答案 0 :(得分:0)
以下是“隐藏方法”的示例。当然,这不是MVP,只是一个例子。
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public Form1()
{
Text = "First Form";
Button button;
Controls.Add(button = new Button { Text = "Launch 2nd Form", AutoSize = true, Location = new Point(10, 10) });
button.Click += (s, e) => new Form2 { StartPosition = FormStartPosition.Manual, Location = new Point(Right, Top) }.Show(this);
}
}
class Form2 : Form
{
public Form2()
{
Text = "Second Form";
dirty = true;
}
private bool dirty;
protected override void OnClosing(CancelEventArgs e)
{
DialogResult result;
if (dirty && (result = new ConfirmSaveForm().ShowDialog(this)) != DialogResult.No)
{
if (Owner != null)
Owner.Activate();
Hide();
e.Cancel = true;
SaveAsync(result == DialogResult.Cancel);
}
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
Trace.WriteLine("Second Form Closed");
base.OnClosed(e);
}
private void SaveAsync(bool fail)
{
SaveAsyncBegin();
var sad = new Action<bool>(PerformAsyncSave);
sad.BeginInvoke(fail, (ar) =>
{
try { sad.EndInvoke(ar); }
catch (Exception ex) { Invoke(new Action<Exception>(SaveAsyncException), ex); return; }
Invoke(new Action(SaveAsyncEnd));
}, null);
}
private void SaveAsyncBegin()
{
// Update UI for save
}
private void PerformAsyncSave(bool fail)
{
Trace.WriteLine("Begin Saving");
Thread.Sleep(1000); // Do some work
if (fail)
{
Trace.WriteLine("Failing Save");
throw new Exception("Save Failed");
}
dirty = false;
}
private void SaveAsyncEnd()
{
Trace.WriteLine("Save Succeeded");
Close();
}
private void SaveAsyncException(Exception ex)
{
Trace.WriteLine("Save Failed");
Show();
MessageBox.Show(this, ex.Message, "Save Failed", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
class ConfirmSaveForm : Form
{
public ConfirmSaveForm()
{
Text = "Confirm Save";
FormBorderStyle = FormBorderStyle.FixedDialog;
ControlBox = false;
ClientSize = new Size(480, 50);
StartPosition = FormStartPosition.CenterParent;
Controls.Add(new Button { Text = "Yes, Fail", DialogResult = DialogResult.Cancel, Size = new Size(150, 30), Location = new Point(10, 10) });
Controls.Add(new Button { Text = "Yes, Succeed", DialogResult = DialogResult.Yes, Size = new Size(150, 30), Location = new Point(160, 10) });
Controls.Add(new Button { Text = "No", DialogResult = DialogResult.No, Size = new Size(150, 30), Location = new Point(320, 10) });
AcceptButton = Controls[0] as IButtonControl;
}
}