之前寫過一篇博客 關於 ScrollViewer 和滾動輪劫持(scroll-wheel-hijack),裡面介紹了 ScrollViewer 的滾動輪劫持問題,以及如果解決。當時的做法是繼承 ScrollViewer 並重寫 OnMouseWheel,全部代碼如下: public class Ex ...
之前寫過一篇博客 關於 ScrollViewer 和滾動輪劫持(scroll-wheel-hijack),裡面介紹了 ScrollViewer 的滾動輪劫持問題,以及如果解決。當時的做法是繼承 ScrollViewer 並重寫 OnMouseWheel,全部代碼如下:
public class ExtendedScrollViewer : ScrollViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
return;
if (VerticalOffset == 0 && e.Delta >= 0)
return;
base.OnMouseWheel(e);
}
}
最近有人提到能不能使用附加屬性處理,所以我就試試。暫時發現簡單地用附加屬性處理,除非查找 VisualTree 上的父節點 ScrollView 並調用它的 LineUp 和 LineDown ,全部代碼如下:
public class ScrollViewerService
{
/// <summary>
/// 從指定元素獲取 CanScrollOuter 依賴項屬性的值。
/// </summary>
/// <param name="obj">從中讀取屬性值的元素。</param>
/// <returns>從屬性存儲獲取的屬性值。</returns>
public static bool GetCanScrollOuter(DependencyObject obj) => (bool)obj.GetValue(CanScrollOuterProperty);
/// <summary>
/// 將 CanScrollOuter 依賴項屬性的值設置為指定元素。
/// </summary>
/// <param name="obj">對其設置屬性值的元素。</param>
/// <param name="value">要設置的值。</param>
public static void SetCanScrollOuter(DependencyObject obj, bool value) => obj.SetValue(CanScrollOuterProperty, value);
/// <summary>
/// 標識 CanScrollOuter 依賴項屬性。
/// </summary>
public static readonly DependencyProperty CanScrollOuterProperty =
DependencyProperty.RegisterAttached("CanScrollOuter", typeof(bool), typeof(ScrollViewerService), new PropertyMetadata(default(bool), OnCanScrollOuterChanged));
private static void OnCanScrollOuterChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = (bool)args.OldValue;
var newValue = (bool)args.NewValue;
if (newValue == false)
return;
var target = obj as ScrollViewer;
target.PreviewMouseWheel += (s, e) =>
{
if (target.ViewportHeight + target.VerticalOffset >= target.ExtentHeight && e.Delta <= 0
|| target.VerticalOffset == 0 && e.Delta >= 0)
{
var parent = target.GetVisualAncestors().OfType<ScrollViewer>().FirstOrDefault();
if (parent == null)
return;
if (e.Delta < 0)
parent.LineDown();
else
parent.LineUp();
}
};
}
}
處理不夠優雅,但將就著用吧。
參考
ScrollViewer.OnMouseWheel(MouseWheelEventArgs) Method (System.Windows.Controls) Microsoft Docs
MouseWheelEventArgs.Delta Property (System.Windows.Input) Microsoft Docs
ScrollViewer.ExtentHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.ViewportHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.VerticalOffset Property (System.Windows.Controls) Microsoft Docs