我正在使用Gtk#创建一个简单的桌面应用程序,当用户点击一个按钮时,我想显示一个"加载指示符" 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 Community Edition 6.0.2
Gtk#version:2.12.38
答案 0 :(得分:1)
在阅读guide响应式Mono应用程序并通过Twitter向Miguel de Icaza询问之后,我找到了这样做的方法。
需要考虑的事项:
1)永远不要创建或尝试修改其他线程的UI元素。
2)如果你需要从另一个线程修改UI控件,请使用该线程内的Application.Invoke()方法。
3)MessageDialog类的Run()方法等待用户交互关闭,即单击关闭按钮或调用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();
}
}
演示: