MaterialDesignInXamlToolkit icon indicating copy to clipboard operation
MaterialDesignInXamlToolkit copied to clipboard

Using a TabControl triggers a TargetInvocationException at App shutdown, when the WPF Control is hosted in a Winform Elementhost

Open svengl opened this issue 1 year ago • 2 comments

Bug explanation

To reproduce this bug, create a Winform app (tested in .NET 8), add an Elementhost (add from code behind since it is not in the Toolbox anymore...) and host a WPF UserControl which contains a TabControl. This will display fine until you close the app. During shutdown, the TargetInvocationException will be thrown. The call stack is hardly helpful since these are shutdown calls. Other controls are apparently not affected and work fine.

Setting the TabControl Style to x:Null will not trigger the exception anymore, so it is definitely something in the TabControl style.

The "source" object of the exception being found in the WeakEventManager.cs seems to be a Scrollviewer whose parent is a "ColorZone". Hope this hint helps.

Version

4.9.0

svengl avatar Jan 20 '24 21:01 svengl

I investigated this a little bit The culprit are the following attached properties in the TabControl style: Inside the ControlTemplate, one can find:

<ScrollViewer wpf:ScrollViewerAssist.BubbleVerticalScroll="True" wpf:ScrollViewerAssist.SupportHorizontalScroll="True"

Removing these attached properties fixes the issue. I digged a bit further and see that the ScrollViewerAssist uses a WeakEventManager to listen to the ScrollViewer Loaded/Unloaded Events:

In ScrollViewerAssist.cs: WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Loaded), OnLoaded); WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Unloaded), OnUnloaded);

When the Winform App with the Elementhost shuts down, the stacktrace indeed shows that the error happens during the cleanup of the WeakEventManager

System.Private.CoreLib.dll!System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(object obj, System.Span copyOfArgs, System.Reflection.BindingFlags invokeAttr) Line 176 C# System.Private.CoreLib.dll!System.Reflection.MethodBaseInvoker.InvokeWithOneArg(object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture) Line 122 C# WindowsBase.dll!System.Windows.WeakEventManager.Purge(object source, object data, bool purgeAll) Line 671 C# WindowsBase.dll!MS.Internal.WeakEventTable.Purge(bool purgeAll) Line 295 C# WindowsBase.dll!MS.Internal.WeakEventTable.OnShutDown() Line 359 C#

The actual exception is: System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation. The calling thread cannot access....

I am a little clueless how to fix this, since the exception occurs in .net code?! Anybody any idea?

svengl avatar Feb 10 '24 21:02 svengl

I also encountered this problem, and this exception did not appear in 4.8 of the MaterialDesignThemes version

Foreverrrrrr avatar May 09 '24 09:05 Foreverrrrrr