我有一个滚动查看器,里面有几个列表框。问题是如果用户使用鼠标中键滚动滚动查看器,而鼠标位于列表视图上方。列表视图将其内部滚动查看器滚动到底部,然后继续捕获鼠标,防止包含滚动查看器滚动。
关于如何处理这个的任何想法?
答案 0 :(得分:41)
之所以发生这种情况,是因为ListView
的(实际上是ListBox
)内容模板本身就会用ScrollViewer
包装其项目。
最简单的方法是通过为内部Template
删除自己的ListView
来禁用它,不会创建ScrollViewer
:
<ListView>
<ListView.Template>
<ControlTemplate>
<ItemsPresenter></ItemsPresenter>
</ControlTemplate>
</ListView.Template>
...
</ListView>
如果你在ListView中有一个ListView(这是我的情况),BTW也会发生同样的情况。
答案 1 :(得分:3)
您是否尝试停用ListView's
ScrollBars
?
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled" />
答案 2 :(得分:3)
IMO,处理这种情况的最好方法是创建一个自定义控件:
class MyScrollViewer : ScrollViewer
{
protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
{
base.OnPreviewMouseWheel(e);
if (!e.Handled)
{
e.Handled = true;
this.RaiseEvent(new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = this
});
}
}
}
答案 3 :(得分:1)
受some helpful answers的启发,我实现了一个实现,当内部祖先ScrollViewer(包括来自ListView,ListBox,DataGrid的祖先)滚动超过其顶部/底部时,将其滚动。
我将附加属性应用于App.xaml中的所有ScrollViewer:
<Style TargetType="ScrollViewer" BasedOn="{StaticResource {x:Type ScrollViewer}}">
<Setter Property="local:ScrollViewerHelper.FixMouseWheel" Value="True" />
</Style>
附加属性检测滚动到顶部/底部的位置,并且发生滚动时,会在ScrollViewer的父级上引发鼠标滚轮事件。事件路由将其传递到外部ScrollViewer:
public static class ScrollViewerHelper
{
// Attached property boilerplate
public static bool GetFixMouseWheel(ScrollViewer scrollViewer) => (bool)scrollViewer?.GetValue(FixMouseWheelProperty);
public static void SetFixMouseWheel(ScrollViewer scrollViewer, bool value) => scrollViewer?.SetValue(FixMouseWheelProperty, value);
public static readonly DependencyProperty FixMouseWheelProperty =
DependencyProperty.RegisterAttached("FixMouseWheel", typeof(bool), typeof(ScrollViewerHelper),
new PropertyMetadata(OnFixMouseWheelChanged));
// End attached property boilerplate
static void OnFixMouseWheelChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var scrollViewer = d as ScrollViewer;
if (scrollViewer == null) return;
scrollViewer.PreviewMouseWheel += (s2, e2) =>
{
var parent = scrollViewer.Parent as UIElement;
bool hitTopOrBottom = HitTopOrBottom(e2.Delta, scrollViewer);
if (parent is null || !hitTopOrBottom) return;
var argsCopy = Copy(e2);
parent.RaiseEvent(argsCopy);
};
}
static bool HitTopOrBottom(double delta, ScrollViewer scrollViewer)
{
var contentVerticalOffset = scrollViewer.ContentVerticalOffset;
var atTop = contentVerticalOffset == 0;
var movedUp = delta > 0;
var hitTop = atTop && movedUp;
var atBottom =
contentVerticalOffset == scrollViewer.ScrollableHeight;
var movedDown = delta < 0;
var hitBottom = atBottom && movedDown;
return hitTop || hitBottom;
}
static MouseWheelEventArgs Copy(MouseWheelEventArgs e)
=> new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = e.Source,
};
}
答案 4 :(得分:0)
如果将内部列表视图包装在滚动查看器中,则滚动将起作用。
<ListView ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>