wpf 滚动查看器的子元素阻止使用鼠标滚轮滚动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14348517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Child elements of scrollviewer preventing scrolling with mouse wheel?
提问by Tom
I'm having a problem getting mouse wheel scrolling to work in the following XAML, which I have simplified for clarity:
我在使鼠标滚轮滚动以在以下 XAML 中工作时遇到问题,为了清楚起见,我对其进行了简化:
<ScrollViewer
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
CanContentScroll="False"
>
<Grid
MouseDown="Editor_MouseDown"
MouseUp="Editor_MouseUp"
MouseMove="Editor_MouseMove"
Focusable="False"
>
<Grid.Resources>
<DataTemplate
DataType="{x:Type local:DataFieldModel}"
>
<Grid
Margin="0,2,2,2"
>
<TextBox
Cursor="IBeam"
MouseDown="TextBox_MouseDown"
MouseUp="TextBox_MouseUp"
MouseMove="TextBox_MouseMove"
/>
</Grid>
</DataTemplate>
</Grid.Resources>
<ListBox
x:Name="DataFieldListBox"
ItemsSource="{Binding GetDataFields}"
SelectionMode="Extended"
Background="Transparent"
Focusable="False"
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem"
>
<Setter
Property="Canvas.Left"
Value="{Binding dfX}"
/>
<Setter
Property="Canvas.Top"
Value="{Binding dfY}"
/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</ScrollViewer>
Visually, the result is an area of some known size where DataField
s read from a collection can be represented with TextBox
es which have arbitrary position, size, et cetera. In cases where the ListBox
's styled "area" is too large to display all at once, horizontal and vertical scrolling is possible, but only with the scroll bars.
从视觉上看,结果是一个已知大小的区域,其中DataField
从集合中读取的 s 可以用TextBox
具有任意位置、大小等的 es表示。如果ListBox
的样式“区域”太大而无法一次显示,则可以进行水平和垂直滚动,但只能使用滚动条。
For better ergonomics and sanity, mouse wheel scrolling should be possible, and normally ScrollViewer
would handle it automatically, but the ListBox
appears to be handing those events such that the parent ScrollViewer
never sees them. So far I have only been able to get wheel scrolling working be setting IsHitTestVisible=False
for either the ListBox
or the parent Grid
, but of course none of the child element's mouse events work after that.
为了更好的人体工程学和理智,鼠标滚轮滚动应该是可能的,并且通常ScrollViewer
会自动处理它,但ListBox
似乎正在处理这些事件,以便父母ScrollViewer
永远不会看到它们。到目前为止,我只能IsHitTestVisible=False
为 theListBox
或 parent设置滚轮滚动Grid
,但当然之后没有任何子元素的鼠标事件起作用。
What can I do to ensure the ScrollViewer
sees mouse wheel events while preserving others for child elements?
我该怎么做才能确保ScrollViewer
看到鼠标滚轮事件,同时为子元素保留其他事件?
Edit: I just learned that ListBox
has a built-in ScrollViewer
which is probably stealing wheel events from the parent ScrollViewer
and that specifying a control template can disable it. I'll update this question if that resolves the problem.
编辑:我刚刚了解到它ListBox
有一个内置的ScrollViewer
可能会从父级窃取轮子事件,ScrollViewer
并且指定一个控件模板可以禁用它。如果解决了问题,我会更新这个问题。
采纳答案by Tom
Specifying a ControlTemplate
for the Listbox
which doesn't include a ScrollViewer
solves the problem. See this answerand these two MSDN pages for more information:
ControlTemplate
为Listbox
不包含 a 的指定 a可以ScrollViewer
解决问题。有关更多信息,请参阅此答案和这两个 MSDN 页面:
回答by JoeB
You can also create a behavior and attach it to the parent control (in which the scroll events should bubble through).
您还可以创建一个行为并将其附加到父控件(滚动事件应该在其中冒泡)。
// Used on sub-controls of an expander to bubble the mouse wheel scroll event up
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);
}
}
<SomePanel>
<i:Interaction.Behaviors>
<viewsCommon:BubbleScrollEvent />
</i:Interaction.Behaviors>
</SomePanel>
回答by kahr
Another way of implementing this, is by creating you own ScrollViewer like this:
实现这一点的另一种方法是像这样创建你自己的 ScrollViewer:
public class MyScrollViewer : ScrollViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
var parentElement = Parent as UIElement;
if (parentElement != null)
{
if ((e.Delta > 0 && VerticalOffset == 0) ||
(e.Delta < 0 && VerticalOffset == ScrollableHeight))
{
e.Handled = true;
var routedArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
routedArgs.RoutedEvent = UIElement.MouseWheelEvent;
parentElement.RaiseEvent(routedArgs);
}
}
base.OnMouseWheel(e);
}
}
回答by sean.net
I know it's a little late but I have another solution that worked for me. I switched out my stackpanel/listbox for an itemscontrol/grid. Not sure why the scroll events work properly but they do in my case.
我知道现在有点晚了,但我有另一个对我有用的解决方案。我为 itemscontrol/grid 切换了我的 stackpanel/listbox。不知道为什么滚动事件可以正常工作,但在我的情况下可以。
<ScrollViewer VerticalScrollBarVisibility="Auto" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
<StackPanel Orientation="Vertical">
<ListBox ItemsSource="{Binding DrillingConfigs}" Margin="0,5,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
became
变成了
<ScrollViewer VerticalScrollBarVisibility="Auto" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding DrillingConfigs}" Margin="0,5,0,0" Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>