none
'Dispatcher processing has been suspended' InvalidOperationException when calling ShowDialog

    Question

  • I have the following XAML:

    <TabItem Header="Test1" IsSelected="True"></TabItem>
    <TabItem Header="Test2">
    <StackPanel IsVisibleChanged="OnIsVisibleChanged"></StackPanel>
    </TabItem>

    and the C#:

    Code Snippet

    public void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                if (sender is StackPanel && (sender as StackPanel).IsVisible)
                {
                    SaveFileDialog saveDialog = new SaveFileDialog();
                    ...
                    saveDialog.ShowDialog(this);
                }
            }



    Every time I run the app, and select the second tab, ShowDialog() throws an InvalidOperationException, with the message 'Dispatcher processing has been suspended, but messages are still being processed.' (Full stack trace at bottom of post).

    Also note that Window.ShowDialog() and MessageBox.Show() cause the same error.

    What is causing this? Maybe I am not supposed to call anything that *could* affect dependency properties from a dependency property related event handler (I noticed that IsVisibleChanged is a DependencyPropertyChangedEventHandler) however I can't seem to find any documentation about this.

    I also thought this could be caused by internal nested message processing / use of PushFrame to create a message loop for the dialog. Based on the idea that this could be caused by a threading problem, I changed the code as below, which runs without any problems (Is this a valid workaround?):

    Code Snippet

    public delegate void InvokeDelegate();

            public void InvokeMethod()
            {
                SaveFileDialog saveDialog = new SaveFileDialog();
                saveDialog.Title = "Save As";
                saveDialog.AddExtension = true;
                saveDialog.DefaultExt = ".aim";

                saveDialog.ShowDialog(this);
            }

            public void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                if (sender is StackPanel && (sender as StackPanel).IsVisible)
                {
                    Dispatcher.BeginInvoke(DispatcherPriority.Send, new InvokeDelegate(InvokeMethod));
                }
            }





    Full exception trace:

    System.InvalidOperationException was unhandled
      Message="Dispatcher processing has been suspended, but messages are still being processed."
      Source="WindowsBase"
      StackTrace:
           at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
           at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
           at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
           at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
           at MS.Win32.UnsafeNativeMethods.GetSaveFileName(OPENFILENAME_I ofn)
           at Microsoft.Win32.SaveFileDialog.RunFileDialog(OPENFILENAME_I ofn)
           at Microsoft.Win32.FileDialog.RunDialog(IntPtr hwndOwner)
           at Microsoft.Win32.CommonDialog.ShowDialog(Window owner)
           at TestTabItemOnVisibleDialogError.Window1.OnIsVisibleChanged(Object sender, DependencyPropertyChangedEventArgs e) in C:\Documents and Settings\nick.baker\My Documents\Visual Studio 2005\Projects\TestTabItemOnVisibleDialogError\TestTabItemOnVisibleDialogError\Window1.xaml.cs:line 91
           at System.Windows.UIElement.RaiseDependencyPropertyChanged(EventPrivateKey key, DependencyPropertyChangedEventArgs args)
           at System.Windows.UIElement.OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
           at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
           at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
           at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
           at System.Windows.UIElement.UpdateIsVisibleCache()
           at System.Windows.UIElement.SynchronizeForceInheritProperties(UIElement uiElement, ContentElement contentElement, DependencyObject parent)
           at System.Windows.UIElement.OnVisualParentChanged(DependencyObject oldParent)
           at System.Windows.FrameworkElement.OnVisualParentChanged(DependencyObject oldParent)
           at System.Windows.Media.Visual.FireOnVisualParentChanged(Visual oldParent)
           at System.Windows.Media.Visual.AddVisualChild(Visual child)
           at System.Windows.FrameworkElement.set_TemplateChild(UIElement value)
           at System.Windows.StyleHelper.AddCustomTemplateRoot(FrameworkElement container, UIElement child, Boolean checkVisualParent, Boolean mustCacheTreeStateOnChild)
           at System.Windows.Controls.ContentPresenter.UseContentTemplate.BuildVisualTree(FrameworkElement container)
           at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
           at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
           at System.Windows.FrameworkElement.ApplyTemplate()
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.ContextLayoutManager.UpdateLayout()
           at System.Windows.UIElement.UpdateLayout()
           at System.Windows.Controls.TabItem.OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
           at System.Windows.UIElement.OnPreviewGotKeyboardFocusThunk(Object sender, KeyboardFocusChangedEventArgs e)
           at System.Windows.Input.KeyboardFocusChangedEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
           at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
           at System.Windows.Input.InputManager.ProcessStagingArea()
           at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
           at System.Windows.Input.KeyboardDevice.TryChangeFocus(DependencyObject newFocus, IKeyboardInputProvider keyboardInputProvider, Boolean askOld, Boolean askNew, Boolean forceToNullIfFailed)
           at System.Windows.Input.KeyboardDevice.Focus(DependencyObject focus, Boolean askOld, Boolean askNew)
           at System.Windows.Input.KeyboardDevice.Focus(IInputElement element)
           at System.Windows.UIElement.Focus()
           at System.Windows.Controls.TabItem.SetFocus()
           at System.Windows.Controls.TabItem.OnMouseLeftButtonDown(MouseButtonEventArgs e)
           at System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object sender, MouseButtonEventArgs e)
           at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.ReRaiseEventAs(RoutedEventArgs args, RoutedEvent newEvent)
           at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e)
           at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
           at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
           at System.Windows.Input.InputManager.ProcessStagingArea()
           at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
           at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
           at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
           at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
           at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
           at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
           at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
           at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
           at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
           at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
           at System.Windows.Threading.Dispatcher.Run()
           at System.Windows.Application.RunInternal(Window window)
           at System.Windows.Application.Run(Window window)
           at System.Windows.Application.Run()
           at TestTabItemOnVisibleDialogError.App.Main() in C:\Documents and Settings\nick.baker\My Documents\Visual Studio 2005\Projects\TestTabItemOnVisibleDialogError\TestTabItemOnVisibleDialogError\obj\Debug\App.g.cs:line 0
           at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()

    Monday, February 25, 2008 7:52 PM

Answers

  • This is done on purpose to prevent reentrancy bugs caused by weirdness resulting from altering the visual tree while such an event (which itself has been triggered by the visual tree altering) is firing. If you really must confirm something when the Visible state of a UI element changes (I can't think of a single good reason why you would) delaying with Dispatcher.BeginInvoke is probably the right thing to do.
    Tuesday, February 26, 2008 9:52 PM

All replies

  • This is done on purpose to prevent reentrancy bugs caused by weirdness resulting from altering the visual tree while such an event (which itself has been triggered by the visual tree altering) is firing. If you really must confirm something when the Visible state of a UI element changes (I can't think of a single good reason why you would) delaying with Dispatcher.BeginInvoke is probably the right thing to do.
    Tuesday, February 26, 2008 9:52 PM
  • Thanks for your reply.

    Just for completeness the reason for using IsVisibleChanged is because we need to perform a (deferred) UI update when a certain tab becomes visible, and it just so happens that because the tab is used to trigger an asynchronous process, that process may have completed in the meantime, so we may need to prompt the user to save the results of the process on returning to that tab. In hindsight I may be able to get the same functionality using Loaded and checking IsVisible.
    Wednesday, February 27, 2008 10:15 AM