Advertisement
bobmarley12345

WPF async window closing handler

May 23rd, 2023
715
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.06 KB | None | 0 0
  1. // from:
  2. // https://github.com/AngryCarrot789/FrameControlEx
  3.  
  4.  
  5.  
  6. private bool isHandlingSyncClosing;
  7. private bool isHandlingAsyncClose;
  8. private bool? closeEventResult;
  9.  
  10. protected sealed override void OnClosing(CancelEventArgs e) {
  11.     if (this.isHandlingSyncClosing || this.isHandlingAsyncClose) {
  12.         return;
  13.     }
  14.  
  15.     try {
  16.         this.isHandlingSyncClosing = true;
  17.         this.OnClosingInternal(e);
  18.         if (this.closeEventResult.HasValue) {
  19.             try { // try finally juuust in case...
  20.                 e.Cancel = !this.closeEventResult.Value; // true = close, false = do not close
  21.             }
  22.             finally {
  23.                 this.closeEventResult = null;
  24.             }
  25.         }
  26.         else {
  27.             e.Cancel = true;
  28.         }
  29.     }
  30.     finally {
  31.         this.isHandlingSyncClosing = false;
  32.     }
  33. }
  34.  
  35. /*
  36.     async void is required here
  37.     OnClosing is fired, that sets isHandlingSyncClosing to true and invokes this method which awaits CloseAsync()
  38.  
  39.     During the invocation of CloseAsync, If the call does not require
  40.     real async (e.g. does not use Task.Delay() or whatever):
  41.         CloseAsync will return in the same execution context as OnClosing, meaning isHandlingSyncClosing
  42.         stays true, and OnClosing can access closeEventResult and set the e.Cancel accordingly
  43.  
  44.     However, if the call chain in CloseAsync uses Task.Delay() or something which returns
  45.     a task that is incomplete by the time the async state machine comes to actually "awaiting" it,
  46.     then the behaviour changes:
  47.         OnClosing returns before CloseAsync is completed, setting isHandlingSyncClosing to false, meaning that
  48.         CloseAsyncInternal will manually close the window itself because the original OnClosing was cancelled
  49.  
  50.  
  51.  */
  52. private async void OnClosingInternal(CancelEventArgs e) {
  53.     bool result = await this.CloseAsync();
  54.     if (this.isHandlingSyncClosing) {
  55.         this.closeEventResult = result;
  56.     }
  57. }
  58.  
  59. /// <summary>
  60. /// Closes the window
  61. /// </summary>
  62. /// <returns>Whether the window was closed or not</returns>
  63. public Task<bool> CloseAsync() {
  64.     // return await await Task.Run(async () => await DispatcherUtils.InvokeAsync(this.Dispatcher, this.CloseAsyncInternal));
  65.     return DispatcherUtils.Invoke(this.Dispatcher, this.CloseAsyncInternal);
  66. }
  67.  
  68. private async Task<bool> CloseAsyncInternal() {
  69.     if (await this.OnClosingAsync()) {
  70.         if (!this.isHandlingSyncClosing) {
  71.             try {
  72.                 this.isHandlingAsyncClose = true;
  73.                 await DispatcherUtils.InvokeAsync(this.Dispatcher, this.Close);
  74.                 return true;
  75.             }
  76.             finally {
  77.                 this.isHandlingAsyncClose = false;
  78.             }
  79.         }
  80.  
  81.         return true;
  82.     }
  83.     else {
  84.         return false;
  85.     }
  86. }
  87.  
  88. /// <summary>
  89. /// Called when the window is trying to be closed
  90. /// </summary>
  91. /// <returns>True if the window can close, otherwise false to stop it from closing</returns>
  92. protected virtual Task<bool> OnClosingAsync() {
  93.     return Task.FromResult(true);
  94. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement