WPFのScrollViewerはネストするとビジュアルツリー上で末端の方にあるScrollViewerがマウススクロールイベントを握りつぶしてしまい、上にあるScrollViewerがスクロールできなくなる糞仕様がある。これを末端ScrollViewerのスクロールを無効化し、上のScrollViewerがスクロール出来るようにする。
糞の原因
ScrollViewerがMouseWheelイベントをhandle = trueにしており、ここでスクロールイベントが握りつぶされている。そのため、MouseWheelイベントがScrollViewerより上へバブルしてくれない。
対策
ScrollViewerのPreviewMouseWheelイベントを購読し、握りつぶすこれに代わってMouseWheelを親要素で投げてやる。なお、当然"親"要素で投げてやる必要がある。ScrollViewerで投げると握り潰される。Behavior<ScrollViewer>として書くといい感じ。
public class WheelScrollKillBehavior : Behavior<ScrollViewer>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
}
void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
var newEventArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent
};
((UIElement)AssociatedObject.Parent).RaiseEvent(newEventArgs);
}
}