如何在后台执行进程时显示MessageDialog并在完成后关闭它

时间:2016-08-13 20:56:49

标签: c# mono xamarin-studio gtk#

我正在使用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

1 个答案:

答案 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();
    }
}

演示:

enter image description here