Skip to content

Commit 6ec10e4

Browse files
Followup fix for ScrollViewerAssist PR (#4016)
* Revert "Remove ScrollViewerAssist weak event handlers on WM_DESTROY (#4015)" This reverts commit 177d663. * Fix issue by for BubbleVerticalScroll * Fix issue by for HorizontalScroll * Cleanup: revert not needed signature change
1 parent 177d663 commit 6ec10e4

File tree

1 file changed

+107
-50
lines changed

1 file changed

+107
-50
lines changed

src/MaterialDesignThemes.Wpf/ScrollViewerAssist.cs

Lines changed: 107 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Windows.Interop;
1+
using System.Windows.Interop;
22

33
namespace MaterialDesignThemes.Wpf;
44

@@ -64,25 +64,25 @@ public static PaddingMode GetPaddingMode(DependencyObject element)
6464
private static readonly DependencyProperty HorizontalScrollHookProperty = DependencyProperty.RegisterAttached(
6565
"HorizontalScrollHook", typeof(HwndSourceHook), typeof(ScrollViewerAssist), new PropertyMetadata(null));
6666

67-
private static readonly DependencyProperty HorizontalScrollSourceProperty = DependencyProperty.RegisterAttached(
68-
"HorizontalScrollSource", typeof(HwndSource), typeof(ScrollViewerAssist), new PropertyMetadata(null));
67+
private static readonly DependencyProperty BubbleVerticalScrollHookProperty = DependencyProperty.RegisterAttached(
68+
"BubbleVerticalScrollHook", typeof(HwndSourceHook), typeof(ScrollViewerAssist), new PropertyMetadata(null));
6969

7070
public static readonly DependencyProperty SupportHorizontalScrollProperty = DependencyProperty.RegisterAttached(
7171
"SupportHorizontalScroll", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(false, OnSupportHorizontalScrollChanged));
7272

7373
private static void OnSupportHorizontalScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
7474
{
7575
//Based on: https://blog.walterlv.com/post/handle-horizontal-scrolling-of-touchpad-en.html
76-
if (d is ScrollViewer scrollViewer)
76+
if (d is ScrollViewer sv)
7777
{
78-
if (scrollViewer.IsLoaded)
78+
if (sv.IsLoaded)
7979
{
80-
DoOnLoaded(scrollViewer);
80+
DoOnLoaded(sv);
8181
}
8282
else
8383
{
84-
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Loaded), OnLoaded);
85-
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Unloaded), OnUnloaded);
84+
RegisterForLoadedEvent(sv);
85+
RegisterForUnloadedEvent(sv);
8686
}
8787
}
8888

@@ -94,10 +94,35 @@ static void OnLoaded(object? sender, RoutedEventArgs e)
9494
}
9595
}
9696

97+
static void UnregisterForLoadedEvent(ScrollViewer sv)
98+
{
99+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(sv, nameof(ScrollViewer.Loaded), OnLoaded);
100+
}
101+
102+
static void RegisterForLoadedEvent(ScrollViewer sv)
103+
{
104+
// Avoid double registrations
105+
UnregisterForLoadedEvent(sv);
106+
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(sv, nameof(ScrollViewer.Loaded), OnLoaded);
107+
}
108+
109+
static void UnregisterForUnloadedEvent(ScrollViewer sv)
110+
{
111+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(sv, nameof(ScrollViewer.Unloaded), OnUnloaded);
112+
}
113+
114+
static void RegisterForUnloadedEvent(ScrollViewer sv)
115+
{
116+
// Avoid double registrations
117+
UnregisterForUnloadedEvent(sv);
118+
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(sv, nameof(ScrollViewer.Unloaded), OnUnloaded);
119+
}
120+
97121
static void DoOnLoaded(ScrollViewer sv)
98122
{
99123
if (GetSupportHorizontalScroll(sv))
100124
{
125+
RegisterForUnloadedEvent(sv);
101126
RegisterHook(sv);
102127
}
103128
else
@@ -114,30 +139,23 @@ static void OnUnloaded(object? sender, RoutedEventArgs e)
114139
}
115140
}
116141

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-
123-
static void RemoveHook(ScrollViewer scrollViewer)
142+
static void RemoveHook(ScrollViewer sv)
124143
{
125-
if (scrollViewer.GetValue(HorizontalScrollHookProperty) is HwndSourceHook hook &&
126-
scrollViewer.GetValue(HorizontalScrollSourceProperty) is HwndSource source)
144+
var source = PresentationSource.FromVisual(sv) as HwndSource;
145+
if (source is not null && sv.GetValue(HorizontalScrollHookProperty) is HwndSourceHook hook)
127146
{
128147
source.RemoveHook(hook);
129-
scrollViewer.SetValue(HorizontalScrollHookProperty, null);
148+
sv.SetValue(HorizontalScrollHookProperty, null);
130149
}
131150
}
132151

133-
static void RegisterHook(ScrollViewer scrollViewer)
152+
static void RegisterHook(ScrollViewer sv)
134153
{
135-
RemoveHook(scrollViewer);
136-
if (PresentationSource.FromVisual(scrollViewer) is HwndSource source)
154+
RemoveHook(sv);
155+
if (PresentationSource.FromVisual(sv) is HwndSource source)
137156
{
138157
HwndSourceHook hook = Hook;
139-
scrollViewer.SetValue(HorizontalScrollSourceProperty, source);
140-
scrollViewer.SetValue(HorizontalScrollHookProperty, hook);
158+
sv.SetValue(HorizontalScrollHookProperty, hook);
141159
source.AddHook(hook);
142160
}
143161

@@ -148,15 +166,15 @@ IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled
148166
const int WM_NCDESTROY = 0x0082;
149167
switch (msg)
150168
{
151-
case WM_MOUSEHWHEEL when scrollViewer.IsMouseOver:
169+
case WM_MOUSEHWHEEL when sv.IsMouseOver:
152170
int tilt = (short)((wParam.ToInt64() >> 16) & 0xFFFF);
153-
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + tilt);
171+
sv.ScrollToHorizontalOffset(sv.HorizontalOffset + tilt);
154172
return (IntPtr)1;
155173
case WM_DESTROY:
156174
case WM_NCDESTROY:
157-
RemoveHandlers(scrollViewer);
158-
var source = PresentationSource.FromVisual(scrollViewer) as HwndSource;
159-
source?.RemoveHook(Hook);
175+
UnregisterForLoadedEvent(sv);
176+
UnregisterForUnloadedEvent(sv);
177+
RemoveHook(sv);
160178
break;
161179
}
162180
return IntPtr.Zero;
@@ -166,19 +184,19 @@ IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled
166184

167185
public static readonly DependencyProperty BubbleVerticalScrollProperty = DependencyProperty.RegisterAttached(
168186
"BubbleVerticalScroll", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(false, OnBubbleVerticalScrollChanged));
169-
187+
170188
private static void OnBubbleVerticalScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
171189
{
172-
if (d is ScrollViewer scrollViewer)
190+
if (d is ScrollViewer sv)
173191
{
174-
if (scrollViewer.IsLoaded)
192+
if (sv.IsLoaded)
175193
{
176-
DoOnLoaded(scrollViewer);
194+
DoOnLoaded(sv);
177195
}
178196
else
179197
{
180-
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Loaded), OnLoaded);
181-
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(scrollViewer, nameof(ScrollViewer.Unloaded), OnUnloaded);
198+
RegisterForLoadedEvent(sv);
199+
RegisterForUnloadedEvent(sv);
182200
}
183201
}
184202

@@ -190,10 +208,48 @@ static void OnLoaded(object? sender, RoutedEventArgs e)
190208
}
191209
}
192210

211+
static void UnregisterForLoadedEvent(ScrollViewer sv)
212+
{
213+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(sv, nameof(ScrollViewer.Loaded), OnLoaded);
214+
}
215+
216+
static void RegisterForLoadedEvent(ScrollViewer sv)
217+
{
218+
// Avoid double registrations
219+
UnregisterForLoadedEvent(sv);
220+
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(sv, nameof(ScrollViewer.Loaded), OnLoaded);
221+
}
222+
223+
static void UnregisterForUnloadedEvent(ScrollViewer sv)
224+
{
225+
WeakEventManager<ScrollViewer, RoutedEventArgs>.RemoveHandler(sv, nameof(ScrollViewer.Unloaded), OnUnloaded);
226+
}
227+
228+
static void RegisterForUnloadedEvent(ScrollViewer sv)
229+
{
230+
// Avoid double registrations
231+
UnregisterForUnloadedEvent(sv);
232+
WeakEventManager<ScrollViewer, RoutedEventArgs>.AddHandler(sv, nameof(ScrollViewer.Unloaded), OnUnloaded);
233+
}
234+
235+
static void UnregisterForMouseWheelEvent(ScrollViewer sv)
236+
{
237+
sv.RemoveHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel);
238+
}
239+
240+
static void RegisterForMouseWheelEvent(ScrollViewer sv)
241+
{
242+
// Avoid double registrations
243+
UnregisterForMouseWheelEvent(sv);
244+
sv.AddHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel, true);
245+
}
246+
193247
static void DoOnLoaded(ScrollViewer sv)
194248
{
195249
if (GetBubbleVerticalScroll(sv))
196250
{
251+
RegisterForUnloadedEvent(sv);
252+
RegisterForMouseWheelEvent(sv);
197253
RegisterHook(sv);
198254
}
199255
else
@@ -206,29 +262,29 @@ static void OnUnloaded(object? sender, RoutedEventArgs e)
206262
{
207263
if (sender is ScrollViewer sv)
208264
{
209-
RemoveHook(sv);
265+
UnregisterForUnloadedEvent(sv);
266+
UnregisterForMouseWheelEvent(sv);
210267
}
211268
}
212269

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-
219-
static void RemoveHook(ScrollViewer scrollViewer)
270+
static void RemoveHook(ScrollViewer sv)
220271
{
221-
scrollViewer.RemoveHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel);
272+
var source = PresentationSource.FromVisual(sv) as HwndSource;
273+
if (source is not null && sv.GetValue(BubbleVerticalScrollHookProperty) is HwndSourceHook hook)
274+
{
275+
source.RemoveHook(hook);
276+
sv.SetValue(BubbleVerticalScrollHookProperty, null);
277+
}
222278
}
223279

224-
static void RegisterHook(ScrollViewer scrollViewer)
280+
static void RegisterHook(ScrollViewer sv)
225281
{
226-
RemoveHook(scrollViewer);
227-
if (PresentationSource.FromVisual(scrollViewer) is HwndSource source)
282+
RemoveHook(sv);
283+
if (PresentationSource.FromVisual(sv) is HwndSource source)
228284
{
229285
HwndSourceHook hook = Hook;
230286
source.AddHook(hook);
231-
scrollViewer.AddHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel, true);
287+
sv.SetValue(BubbleVerticalScrollHookProperty, hook);
232288
}
233289

234290
IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
@@ -239,9 +295,10 @@ IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled
239295
{
240296
case WM_DESTROY:
241297
case WM_NCDESTROY:
242-
RemoveHandlers(scrollViewer);
243-
var source = PresentationSource.FromVisual(scrollViewer) as HwndSource;
244-
source?.RemoveHook(Hook);
298+
UnregisterForMouseWheelEvent(sv);
299+
UnregisterForLoadedEvent(sv);
300+
UnregisterForUnloadedEvent(sv);
301+
RemoveHook(sv);
245302
break;
246303
}
247304
return IntPtr.Zero;

0 commit comments

Comments
 (0)