picoe / Eto

Cross platform GUI framework for desktop and mobile applications in .NET
Other
3.52k stars 319 forks source link

Programmatically closing a dialog #2633

Open UCIS opened 3 months ago

UCIS commented 3 months ago

I used a Dialog as a progress/busy indicator for some long-running operations in an application. The Dialog is displayed using ShowModalAsync, locking the parent Form/Dialog, while allowing the application code to start the long running operation and eventually Close the dialog and wait for the ShowModalAsync task to complete and Dispose the form. This seems to work fine sometimes, but breaks down when the operation completes synchronously.

I have tried to wait for the OnShown event to be raised before calling the Close/Dispose methods, and while this seems to work for Wpf it does not seem like a reliable solution, causing different effects on Gtk and possibly not working at all on Mac (#2254).

Is the use of a Dialog as a programmatically controlled progress/busy indicator acceptable? Would there be a better approach to achieve the desired behavior?

Expected Behavior

The dialog opens, blocking the main UI, and closes immediately after, or does not show at all.

Actual Behavior

Steps to Reproduce the Problem

  1. Run the test code below and click the button in the form that appears.
  2. Enabling the form.Close call and running on the Wpf platform produce slightly different results.
  3. (Scheduling the form.Close call on the UI thread seems to work for now)
using Eto.Forms;
using System;

namespace Test {
    class Program {
        [STAThread]
        public static void Main(string[] args) {
            new Application(Eto.Platforms.Gtk).Run(new TestForm()); return;
        }
        class TestForm : Form {
            public TestForm() {
                Content = new Button() { Command = new Command(ButtonClick) };
            }
            async void ButtonClick(object state, EventArgs e) {
                var form = new Dialog();
                _ = form.ShowModalAsync(this);
                //Application.Instance.AsyncInvoke(form.Close);
                //form.Close();
                form.Dispose();
                MessageBox.Show(this, "hi");
            }
        }
    }
}

Specifications