简体   繁体   中英

ShowDialog and Show sometimes throw exception with animated closing window

Im creating a small application for a few friends. The application is done, but I want to make the GUI of it more "professional" so Im making a new GUI to it. Ive stumbled across a weird issue with one of the dialogboxes Im using for data input where sometimes when I use the Close() funcion on it, the showDialog function will sometimes throw a InvalidOperationException with the text "This Visual is not connected to a PresentationSource". If I write the ShowDialog function call in a try catch and catch the exception to prevent it from stopping the application runtime, it works fine and the window in question can still open and close as intended, but it sometimes throws that exception.

The code for opening the window as a dialog (Run from mainwindow on button click):

addCommand win = new addCommand();      //Creates a new instance of the window
win.Left = this.Left;                   //Makes it appear on top of the mainwindow
win.Top = this.Top + 25;

((BlurEffect)appMain.Effect).Radius = 5;//Blurs out the background (Error occurs even with this not added
win.ShowDialog();                   //Shows window as dialog (This is where the exception is thrown
((BlurEffect)appMain.Effect).Radius = 0;//Removes blur when window is closed

Code in the window class:

private void Button_Click(object sender, RoutedEventArgs e)
{
   this.Close();
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
   if (!animationComplete)
   {
      Storyboard sb = Resources["closingAnimation"] as Storyboard;
      sb.Begin(this);
      e.Cancel = true;
   }
}

private void storyboardComplete(object sender, EventArgs e)
{
   animationComplete = true;
   this.Close();
}

A button closes the window to trigger ShowDialog to continue runtime. If the animation has not been played, it cancels the Close and plays the animation, which on completition runs Close again, but with animationComplete set true and allowing the window to close. The animation is a simple doubleanimation adjust height of the window from 92 to 0 to create a "slide in, slide out" effect on the window.

This works something like 50/50. Sometimes it works, other times it throws the exception. Im not sure why it sometimes throws the exception and sometimes not. It seems random.

StackTrace of the exception

StackTrace  "   at System.Windows.Media.Visual.PointToScreen(Point point)\r\n   at
 Microsoft.VisualStudio.DesignTools.WpfTap.WpfVisualTreeService.Adorners.AdornerLayerWindow.UpdatePlacement()\r\n   at 
Microsoft.VisualStudio.DesignTools.WpfTap.WpfVisualTreeService.Adorners.AdornerLayerWindow.<UpdatePlacementAsync>b__77_0(Object obj)\r\n   at 
System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n   at 
System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n   at 
System.Windows.Threading.DispatcherOperation.InvokeImpl()\r\n   at 
System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)\r\n   at 
MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)\r\n   at 
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   at 
System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n   
at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)\r\n   
at System.Windows.Threading.DispatcherOperation.Invoke()\r\n   
at System.Windows.Threading.Dispatcher.ProcessQueue()\r\n   
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n   
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n   
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)\r\n   
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n   
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n   at 
System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)\r\n   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n   at
 MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)\r\n   at
 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)\r\n   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)\r\n   
at System.Windows.Window.ShowHelper(Object booleanBox)\r\n   
at System.Windows.Window.Show()\r\n   
at System.Windows.Window.ShowDialog()\r\n   
at Gigglerekt_Scenebot_v2_GUI_update.MainWindow.btnAddCommand_Click(Object sender, RoutedEventArgs e) in D:\\Development\\C#\\Gigglerekt Scenebot v2 GUI update\\Gigglerekt Scenebot v2 GUI update\\MainWindow.xaml.cs:line 84\r\n   at
 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n   at
 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n   at 
System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)\r\n   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)\r\n   at 
System.Windows.Controls.Primitives.ButtonBase.OnClick()\r\n   at
 System.Windows.Controls.Button.OnClick()\r\n   at
 System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)\r\n   at 
System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)\r\n   at
 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)\r\n   at 
System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)\r\n   
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n   at 
System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n   at
 System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)\r\n   at 
System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)\r\n   at 
System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)\r\n   at 
System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)\r\n   at
 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n   at 
System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n   at 
System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)\r\n   at 
System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)\r\n   at
 System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)\r\n   at System.Windows.Input.InputManager.ProcessStagingArea()\r\n   at 
System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)\r\n   at
 System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)\r\n   at
 System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)\r\n   at
 System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n   at 
System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n   at 
MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n   at
 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)\r\n   at 
System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n   at
 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n   at 
System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)\r\n   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n   at
 MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)\r\n   at
 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)\r\n   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)\r\n   at
 System.Windows.Application.RunDispatcher(Object ignore)\r\n   at 
System.Windows.Application.RunInternal(Window window)\r\n   at
 System.Windows.Application.Run(Window window)\r\n   at 
System.Windows.Application.Run()\r\n   at 
Gigglerekt_Scenebot_v2_GUI_update.App.Main()"   string

Update WindowStyle is set to none, but if I set it to something else (Tested with ToolWindow) the exception LOOKS to not be happening anymore.. Testing more to see if I just got lucky or what happened

Update 2 It does indeed look like exception is gone when windowstyle is NOT set to NONE. This goes regardless if I trigger the closing animation with the windows' X button or the button I have added that closes the window

Update 3 If I instead of closing the window on animation complete, hide it. Then close it in the parent window after it resumes runtime (ShowDialog continues on hidden window as well apperantly), the exception does no longer occur. So until I find out why closing it immediately after animation is done does not work all the time with none windowstyle I guess its a workaround? So a question would be what happens on Close() when WindowStyle is set to None, compared to when WindowStyle is not set to None?

https://msdn.microsoft.com/en-us/library/system.windows.forms.form.show(v=vs.110).aspx

win.Show(this);

the parent (form that spawned the dialog) is not aware that it was closed, setting the parent for this dialog will inform the parent that it closed.

I am assuming that Button_Click is the event handler for your close button. So, change your code like this:

private void Button_Click(object sender, RoutedEventArgs e)
{
      Storyboard sb = Resources["closingAnimation"] as Storyboard;
      sb.Completed += new EventHandler(storyboardComplete);
      sb.Begin(this);
}

private void storyboardComplete(object sender, EventArgs e)
{
   this.Close();
}

and eliminate the Window_Closing event handler. It's been a while since I worked with WPF, so I am assuming that ShowDialog does not give you the "X" close button at the top right of the window, so all you have to worry about is your own close button. And what you want to do when they press that close button is start the animation, and it is actually the end of the animation that really closes the dialog, so leave the this.Close() to occur only on the storyboardComplete event.

Setting the Windowstyle to anything but None allows the window to close without exception being thrown, but this would make the reason for me creating a window for dialog in the first place obsolete.

The fix for this I found for now is making the animation Hide window and in the parent window close it after ShowDialog resumes runtime. The exception does not happen, even with WindowStyle set to none.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM