5

We are having multiple issues with this exception but I cannot find technical documentation about the real cause of the issue, all the possible sources for this error and what should we avoid to avoid having the exception.

I have read the following:

The dispatcher processing is suspended to avoid reentrancy problems when updating the visual tree.

But I'm unsure about what means 'updating the visual tree' and what causes a message to be sent to the Dispatcher and reproduces the issue.

The following sample code reproduces the issue:

XAML

<Window x:Class="SuspendedPOF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" 
        Height="350" 
        Width="525">
    <StackPanel>
        <Button Content="1" x:Name="Button1"  IsVisibleChanged="Button1_OnIsVisibleChanged" />
    </StackPanel>
</Window>

C# Code

using System.Windows;

namespace SuspendedPOF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button1_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            MessageBox.Show("Hello");
        }
    }
}

The MessageBox call is not the only one that fires this exception, things like Focus sometimes are problematic as well.

Any help would be great.

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207

2 Answers2

5

The point is that potentially you are trying to change the visual state of your button in the event handler which manages its visual changes (i.e. its visibility). This could lead to an infinite loop (a "reentrancy problems" as you read) and this is also the reason of the InvalidOperationException, that you obtain.

To avoid this issue, you have to defer the MessageBox opening by using the Dispatcher. Then in the Button1_OnIsVisibleChanged method, use this code:

Dispatcher.BeginInvoke(new Action(() => System.Windows.MessageBox.Show("Hello")),
    System.Windows.Threading.DispatcherPriority.Normal);

instead of directly calling the MessageBox Show static method.

Il Vic
  • 5,576
  • 4
  • 26
  • 37
  • Ok, but how can I know at development time that the event handler is one of the problematic ones and that the method inside the event handler could modify the visual state of the button? The messagebox does not look like it could modify the visual state of the button – Ignacio Soler Garcia Feb 03 '16 at 14:04
  • @IgnacioSolerGarcia I believe you (or your collegues) should ask yourself if the code which handles the `IsVisibleChanged` event of a control is trying to change the visual state of the same control. I guess there is no other way. For example showing a message box can potentially hide your control (consider if the message box appears _right_ over it). In this case you have to use the `Dispatcher`, otherwise you need not. – Il Vic Feb 03 '16 at 15:15
  • Honestly, this sounds crazy. Not having into account that launching things with BeginInvoke makes then not synchronous so the flows can vary between executions ... – Ignacio Soler Garcia Feb 03 '16 at 15:44
  • @IgnacioSolerGarcia, I am sorry but I can't understand what sounds crazy for you. Do you mean using the `BeginInvoke` method? – Il Vic Feb 04 '16 at 09:05
  • No, I mean first knowing if the code which handles the event ends up in the potentially big call tree modifying something of the visual tree and second knowing which events manage visual states of every control (including 3rd party like Telerik or DevExpress) – Ignacio Soler Garcia Feb 04 '16 at 09:33
  • @IgnacioSolerGarcia, I see your point of view. Personally I could not find any specific documentation regarding an accurate way for identifying a potentially "dangerous" method – Il Vic Feb 04 '16 at 11:45
  • And somehow this is related to the OS. The application runs more or less ok on Win7 but in W8.1 or W10 the exception is thrown much more often not sure why. – Ignacio Soler Garcia Feb 04 '16 at 18:27
0

As far as I know there is no way to know when you are handling an event that can modify the visual state of the control nor there is a way knowing if your actions will modify the visual state of the UI so it is just a matter of putting BeingInvokes whenever you find a crash ... :S

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207