如何在后台执行进程时显示 MessageDialog 并在完成后关闭它
How to Show a MessageDialog while executing a process in background and close it after finished
我正在使用 Gtk# 创建一个简单的桌面应用程序,当用户单击一个按钮时,我想显示一个 "loading indicator" MessageDialog 并在后台进行一些处理,当该过程完成时关闭对话框并更新 UI.
中的一些控件
我对 Gtk# 和 Mono 很陌生,所以我的代码如下所示:
protected void OnBtnClicked(object sender, EventArgs e)
{
try
{
Task.Factory.StartNew(() =>
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.None, "Processing...");
dlg.Run();
//Some sync calls to remote services
//...
//The process finished so close the Dialog
dlg.Destroy();
//Here: Update the UI with remote service's response
//txtResult.Buffer.Text = result.Message;
});
}
catch (Exception ex)
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, ex.Message);
dlg.Title = "Error";
dlg.Run();
dlg.Destroy();
}
}
这段代码显示了 MessageDialog,但它从未关闭。
单声道版本:4.4.2
IDE:Xamarin Studio 社区版 6.0.2
Gtk# 版本:2.12.38
在阅读 guide for responsive Mono applications and asking to Miguel de Icaza through Twitter 之后,我找到了这样做的方法。
注意事项:
1) 切勿从另一个线程创建或尝试修改 UI 元素。
2) 如果您需要从另一个线程修改 UI 控件,请在该线程内使用 Application.Invoke() 方法。
3) MessageDialog class 中的 运行() 方法等待用户交互关闭,即单击关闭按钮或调用 Close/Destroy 事件的东西。在这种情况下使用该方法是错误的,因为我将从我的代码中关闭 MessageDialog,因此显示对话框的正确方法是 Show()。
考虑到这一点,我的最终代码如下所示:
protected void OnBtnClicked(object sender, EventArgs e)
{
try
{
var mdCalculate = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.None, "Processing...");
mdCalculate.Title = "Calculate";
mdCalculate.Show();
Task.Factory.StartNew(() =>
{
//Some sync calls to remote services
//...
//returns the data I will show in the UI, lets say it's a string
return someData;
}).ContinueWith((prevTask) =>
{
Application.Invoke((send, evnt) =>
{
txtResult.Buffer.Text = prevTask.Result; //this is the string I returned before (someData)
mdCalculate.Hide();
mdCalculate.Destroy();
});
});
}
catch (Exception ex)
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, ex.Message);
dlg.Title = "Error";
dlg.Run();
dlg.Destroy();
}
}
演示:
我正在使用 Gtk# 创建一个简单的桌面应用程序,当用户单击一个按钮时,我想显示一个 "loading indicator" MessageDialog 并在后台进行一些处理,当该过程完成时关闭对话框并更新 UI.
中的一些控件我对 Gtk# 和 Mono 很陌生,所以我的代码如下所示:
protected void OnBtnClicked(object sender, EventArgs e)
{
try
{
Task.Factory.StartNew(() =>
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.None, "Processing...");
dlg.Run();
//Some sync calls to remote services
//...
//The process finished so close the Dialog
dlg.Destroy();
//Here: Update the UI with remote service's response
//txtResult.Buffer.Text = result.Message;
});
}
catch (Exception ex)
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, ex.Message);
dlg.Title = "Error";
dlg.Run();
dlg.Destroy();
}
}
这段代码显示了 MessageDialog,但它从未关闭。
单声道版本:4.4.2
IDE:Xamarin Studio 社区版 6.0.2
Gtk# 版本:2.12.38
在阅读 guide for responsive Mono applications and asking to Miguel de Icaza through Twitter 之后,我找到了这样做的方法。
注意事项:
1) 切勿从另一个线程创建或尝试修改 UI 元素。
2) 如果您需要从另一个线程修改 UI 控件,请在该线程内使用 Application.Invoke() 方法。
3) MessageDialog class 中的 运行() 方法等待用户交互关闭,即单击关闭按钮或调用 Close/Destroy 事件的东西。在这种情况下使用该方法是错误的,因为我将从我的代码中关闭 MessageDialog,因此显示对话框的正确方法是 Show()。
考虑到这一点,我的最终代码如下所示:
protected void OnBtnClicked(object sender, EventArgs e)
{
try
{
var mdCalculate = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.None, "Processing...");
mdCalculate.Title = "Calculate";
mdCalculate.Show();
Task.Factory.StartNew(() =>
{
//Some sync calls to remote services
//...
//returns the data I will show in the UI, lets say it's a string
return someData;
}).ContinueWith((prevTask) =>
{
Application.Invoke((send, evnt) =>
{
txtResult.Buffer.Text = prevTask.Result; //this is the string I returned before (someData)
mdCalculate.Hide();
mdCalculate.Destroy();
});
});
}
catch (Exception ex)
{
var dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, ex.Message);
dlg.Title = "Error";
dlg.Run();
dlg.Destroy();
}
}
演示: