問題
ScrollViewerの中にScrollViewer(またはScrollViewerを内包するListViewやDataGrid)があるとき、マウススクロールが意図した通りに行われません。
原因
入れ子になったScrollViewerの下位ScrollViewerにMouseWheelEventが常にHandleされているため、上位ScrollViewerにスクロールイベントが到達しないことが原因です。
対処法
その1:TemplateからScrollViewerを除外する
下位にあるScrollViewerを使った要素からScrollViewerを取り除くことで対処する方法です。
xaml
<ListView>
<ListView.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListView.Template>
...
</ListView>
その2:MouseWheelEventを強制的に発生させる
上位ScrollViewer(またはMouseWheelEventを扱う要素)がMouseWheelEventを捕捉できるように下位のScrollViewerより先にMouseWheelEventを捕捉し、改めてイベントを送出します。
Behavior
public sealed class BubbleScrollEvent : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
base.OnDetaching();
}
void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
e2.RoutedEvent = UIElement.MouseWheelEvent;
AssociatedObject.RaiseEvent(e2);
}
}
xaml
<SomePanel>
<i:Interaction.Behaviors>
<viewsCommon:BubbleScrollEvent />
</i:Interaction.Behaviors>
</SomePanel>
注意点
DataGridの場合はTemplateを書き換えるとRowHeaderがなくなってしまい表示が崩れます。
これは対処法その2を使うことで回避可能です。
参考
ここに掲載したコードは下記リンクのページから引用しています。