Skip to content

Commit 177d663

Browse files
Remove ScrollViewerAssist weak event handlers on WM_DESTROY (#4015)
In a use case where a TabControl is hosted in an ElementHost inside of a WinForms application, the handlers were not removed, and thus an exception was thrown during application shutdown.
1 parent 505ea07 commit 177d663

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

src/MaterialDesignThemes.Wpf/ScrollViewerAssist.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ static void OnUnloaded(object? sender, RoutedEventArgs e)
114114
}
115115
}
116116

117+
static void RemoveHandlers(ScrollViewer scrollViewer)
118+
{
119+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(scrollViewer, nameof(ScrollViewer.Loaded), OnLoaded);
120+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(scrollViewer, nameof(ScrollViewer.Unloaded), OnUnloaded);
121+
}
122+
117123
static void RemoveHook(ScrollViewer scrollViewer)
118124
{
119125
if (scrollViewer.GetValue(HorizontalScrollHookProperty) is HwndSourceHook hook &&
@@ -138,12 +144,20 @@ static void RegisterHook(ScrollViewer scrollViewer)
138144
IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
139145
{
140146
const int WM_MOUSEHWHEEL = 0x020E;
147+
const int WM_DESTROY = 0x0002;
148+
const int WM_NCDESTROY = 0x0082;
141149
switch (msg)
142150
{
143151
case WM_MOUSEHWHEEL when scrollViewer.IsMouseOver:
144152
int tilt = (short)((wParam.ToInt64() >> 16) & 0xFFFF);
145153
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + tilt);
146154
return (IntPtr)1;
155+
case WM_DESTROY:
156+
case WM_NCDESTROY:
157+
RemoveHandlers(scrollViewer);
158+
var source = PresentationSource.FromVisual(scrollViewer) as HwndSource;
159+
source?.RemoveHook(Hook);
160+
break;
147161
}
148162
return IntPtr.Zero;
149163
}
@@ -196,6 +210,12 @@ static void OnUnloaded(object? sender, RoutedEventArgs e)
196210
}
197211
}
198212

213+
static void RemoveHandlers(ScrollViewer scrollViewer)
214+
{
215+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(scrollViewer, nameof(ScrollViewer.Loaded), OnLoaded);
216+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(scrollViewer, nameof(ScrollViewer.Unloaded), OnUnloaded);
217+
}
218+
199219
static void RemoveHook(ScrollViewer scrollViewer)
200220
{
201221
scrollViewer.RemoveHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel);
@@ -204,7 +224,28 @@ static void RemoveHook(ScrollViewer scrollViewer)
204224
static void RegisterHook(ScrollViewer scrollViewer)
205225
{
206226
RemoveHook(scrollViewer);
207-
scrollViewer.AddHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel, true);
227+
if (PresentationSource.FromVisual(scrollViewer) is HwndSource source)
228+
{
229+
HwndSourceHook hook = Hook;
230+
source.AddHook(hook);
231+
scrollViewer.AddHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel, true);
232+
}
233+
234+
IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
235+
{
236+
const int WM_DESTROY = 0x0002;
237+
const int WM_NCDESTROY = 0x0082;
238+
switch (msg)
239+
{
240+
case WM_DESTROY:
241+
case WM_NCDESTROY:
242+
RemoveHandlers(scrollViewer);
243+
var source = PresentationSource.FromVisual(scrollViewer) as HwndSource;
244+
source?.RemoveHook(Hook);
245+
break;
246+
}
247+
return IntPtr.Zero;
248+
}
208249
}
209250

210251
// This relay is only needed because the UIElement.AddHandler() has strict requirements for the signature of the passed Delegate

0 commit comments

Comments
 (0)