0

I make a method called Instance that allow me to have a single instance of the Settings window, like this:

    public static async Task<Settings> Instance()
    {
        if (AppWindow == null)
        {
            AppWindow = new Settings();

            AppWindow.Closing += async (x, y) =>
            {
                bool close = await AppWindow.CheckSettings();
                y.cancel = (close) ? true : false;
                AppWindow = null;
            };
        }

        return AppWindow;
    }

the CheckSettings have this structure:

private async Task<bool> CheckSettings()
{   
     //just as example
    return true;
}

the method Instance() tell me that there is no await operator inside. Why happen this?

I need to ask also other questions:

  1. Can this logic used inside a property instead of Instance method? How?
  2. Is possible close the window without implement a Task<bool>

UPDATE

based on the helpful answer and comments on this great community I have edited the method as this (now is a property):

    public static Settings Instance
    {
        get
        {
            if (AppWindow == null)
            {
                AppWindow = new Settings();

                AppWindow.Closing += async (x, y) =>
                {
                    bool close = await AppWindow.CheckSettings();
                    y.Cancel = close;

                    //AppWindow.Close();
                    //AppWindow = null;
                };
            }

            return AppWindow;
        }
    }

the problem is that the Cancel does not await the CheckSettings()

1 Answers1

3

Set the Cancel property to true before you call your async method:

public static Settings Instance
{
    get
    {
        if (AppWindow == null)
        {
            AppWindow = new Settings();
            //attach the event handler
            AppWindow.Closing += AppWindow_Closing;
        }
        return AppWindow;
    }
}

private static async void AppWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    e.Cancel = true;

    //call the async method
    bool close = await AppWindow.CheckSettings();
    if (close)
    {
        AppWindow win = (AppWindow)sender;
        //detach the event handler
        AppWindow.Closing -= AppWindow_Closing;
        //...and close the window immediately
        win.Close();
        AppWindow = null;
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • The OP has no idea whether they want to cancel the closing or not before they call the method. The whole point of the method is to determine if they should be cancelling the closing of the form. You now can't ever close this form. – Servy Feb 27 '18 at 16:24
  • Yes? The window will only be closed if CheckSettings returns true. What's your point? – mm8 Feb 27 '18 at 16:25
  • And then it will be cancelled again, and the form will never close. – Servy Feb 27 '18 at 16:25
  • No. Because the event handler is detached once the CheckSettings method returns true. The "form" is then closed as expected. – mm8 Feb 27 '18 at 16:26
  • You should try the code (or at least read it a bit more carefully) before you downvote. – mm8 Feb 27 '18 at 16:27
  • 1
    @mm8 I think your solution is good, I upvoted your answer but I does not have enough rep unfortunately, anyway, when the `win.Close()` line is reached I get this: `cannot set visibility or call show or showdialog after window has closed` do you know exactly why happen this? – PRENDETEVELO NEL CULO Feb 27 '18 at 16:29
  • You can't reuse a closed window. You need to create a new instance of the Settings window once it has been closed. My code sample does work. – mm8 Feb 27 '18 at 16:30
  • @mm8 yep, I'm closing the instance of the sender (win) so should work 'cause is your code – PRENDETEVELO NEL CULO Feb 27 '18 at 16:35
  • @FacundoColidio: Please provide a compilable repo of your issue including all relevant classes if you need any further help on this: https://stackoverflow.com/help/mcve – mm8 Feb 27 '18 at 16:37
  • @mm8 I think my issue is related to `AppWindow` I declared it in this way: `static Settings AppWindow;` why you have casted it? – PRENDETEVELO NEL CULO Feb 27 '18 at 16:43
  • I just cast the sender argument to the actual window that tries to close itself. I guess you only have a single instance of AppWindow but I can't really tell. – mm8 Feb 27 '18 at 16:45
  • @mm8 the `AppWindow` variable in my case only store the `Settings` instance, should I cast as Settings? it's not clear – PRENDETEVELO NEL CULO Feb 27 '18 at 16:47
  • AppWindow should be the same as win. So you probably don't even need to cast. Just do AppWindow.Close() instead of win.Close(). – mm8 Feb 27 '18 at 16:48
  • @mm8 are you sure your code working? I get the same error `cannot set visibility or call show or showdialog after window has closed` also adding AppWindow.Close() – PRENDETEVELO NEL CULO Feb 27 '18 at 17:08
  • It's working for a normal window. If it's not working in your context, you need to provide an example of what your context really is. Please refer to the link I supplied in one of my previous comment for more information about how to do this. – mm8 Feb 27 '18 at 17:11
  • @mm8 please could you check this: https://files.fm/u/gm9t7f98 I prepared a working example, you only need to run it thans – PRENDETEVELO NEL CULO Feb 27 '18 at 17:19
  • @FacundoColidio: Your example works like a charm on my end provided that you set the Cancel property to true in the event handler as I suggested in my answer and include the MahApps.Metro resource dictionaries in your App.xaml. – mm8 Feb 28 '18 at 20:43
  • @mm8 this is weird, please read my other question related to this problem, for me, your solution does not work – PRENDETEVELO NEL CULO Mar 01 '18 at 10:22
  • When I try to close the `Window` I get the exception `System.InvalidOperationException: 'Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing.'` on the `Close()` call. – AntikM Jun 28 '23 at 09:17