WPF Window closing and async / await

 

Partea cea mai buna la async/await este ca acest cod se scrie usor .Usurinta aceasta vine de la un State Machine ( vezi text  sau video  ) si care aduce penalitati de performanta daca nu e folosit cum trebuie (https://ayende.com/blog/174689/the-cost-of-the-async-state-machine )

Vreau sa discut despre un async/ await specific, pe Windows_Closing din WPF. Trebuia sa chem o functie async . Am zis, nimic mai usor:

private async void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{

await MyFunc();

}

 

Acolo, desi pui async pe eveniment si await pe un functie ce ruleaza async, totusi aplicatia se inchide. De ce? As vrea  sa stiu – probabil se inchide pe un thread separat.

Am zis, ok , pun e.Cancel=true la inceput si apoi pe false.


private async void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{

e.Cancel=true;

await MyFunc();

e.Cancel=false;

}

 

Iar nu merge . Nu se mai inchidea.

Am zis, ok, il pacalesc cu scot async de pe eveniment si pun .Result()

private async void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{


var  t= MyFunc().Result;


}

Acum se bloca ( configureAwait, Cleary , https://msdn.microsoft.com/en-us/magazine/dn605875.aspx )

In disperare de cauza , am revenit la old good threads:

bool Cancel;
private void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{

        this.Title = "aaaa";


        var _thread = new Thread(new ThreadStart(() => { Cancel = WaitMe(); }));
        _thread.Start();
        _thread.Join();
        e.Cancel = Cancel;




    }
    bool WaitMe()
    {
        var x = WaitOneMinute().Result;
        return !x;
    }

    async Task<bool> WaitOneMinute()
    {
        await Task.Delay(5 * 1000);        
        var res=MessageBox.Show("Close ?","Close application?",MessageBoxButton.OKCancel);
        return res == MessageBoxResult.OK;
    }

 

Si asa a mers…

 

5 thoughts on “WPF Window closing and async / await

  1. Pana la urma async-await nu e asa simplu cum pare. Imi placea mai mult BeginInvoke-ul, care era mult mai simplu. Event handlerele nu pot fi await-uite. Sunt doar lansate si uitate. De exemplu codul de mai jos afiseaza:
    Click
    MyEvent1
    MyEvent2

    using System;
    using System.Threading.Tasks;
    using System.Windows;

    namespace WpfApplication3
    {
    public partial class MainWindow : Window
    {
    event EventHandler MyEvent;

    public MainWindow()
    {
    InitializeComponent();
    MyEvent += MainWindow_MyEvent1;
    MyEvent += MainWindow_MyEvent2;
    MyButton.Click += MyButton_Click;
    }

    private async void MainWindow_MyEvent1(object sender, EventArgs e)
    {
    await Task.Delay(1);
    MyTextBlock.Text += “MyEvent1\r\n”;
    }

    private async void MainWindow_MyEvent2(object sender, EventArgs e)
    {
    await Task.Delay(1);
    MyTextBlock.Text += “MyEvent2\r\n”;
    }

    private void MyButton_Click(object sender, RoutedEventArgs e)
    {
    MyEvent(this, EventArgs.Empty);
    MyTextBlock.Text += “Click\r\n”;
    }
    }
    }

  2. Metoda veche, care s-ar putea sa functioneze de pe vremea lui Ceausescu:

    using System.ComponentModel;
    using System.Windows;

    namespace WpfApplication3
    {
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    Closing += MainWindow_Closing;
    }

    private void MainWindow_Closing(object sender, CancelEventArgs e)
    {
    Dispatcher.Invoke(() =>
    e.Cancel = MessageBox.Show(“Close?”, “Close”,
    MessageBoxButton.OKCancel) == MessageBoxResult.Cancel);
    }
    }
    }

  3. For non-blocking you can cancel and retrigger the closing.

    using System.ComponentModel;
    using System.Threading.Tasks;
    using System.Windows;

    namespace WpfApplication3
    {
    public partial class MainWindow : Window
    {
    bool closing;

    public MainWindow()
    {
    InitializeComponent();
    Closing += MainWindow_Closing;
    }

    void MainWindow_Closing(object sender, CancelEventArgs e)
    {
    if (!closing)
    {
    closing = true;
    e.Cancel = true;
    BeforeClosingAsync();
    }
    }

    async void BeforeClosingAsync()
    {
    await Task.Delay(3000);
    Close();
    }
    }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *