我在使用鼠标滚轮在以下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>
从视觉上看,结果是一个已知大小的区域,其中从集合中读取的DataField
可以用TextBox
es表示,它们具有任意位置,大小等等。如果ListBox
的样式“区域”太大而无法一次显示,则可以进行水平和垂直滚动,但只能使用滚动条。
为了更好的人体工程学和理智,应该可以滚动鼠标滚轮,通常ScrollViewer
会自动处理它,但ListBox
似乎正在处理这些事件,以便父ScrollViewer
永远不会见到他们到目前为止,我只能让滚轮滚动工作为IsHitTestVisible=False
或父ListBox
设置Grid
,但当然没有子元素的鼠标事件工作。
我可以做些什么来确保ScrollViewer
看到鼠标滚轮事件,同时为子元素保留其他事件?
编辑:我刚刚得知ListBox
有一个内置的ScrollViewer
可能会从父ScrollViewer
窃取轮子事件,并且指定控件模板可以禁用它。如果能解决问题,我会更新这个问题。
答案 0 :(得分:50)
您还可以创建一个行为并将其附加到父控件(滚动事件应该在其中通过)。
// 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>
答案 1 :(得分:12)
为不包含ControlTemplate
的{{1}}指定Listbox
可解决问题。有关详细信息,请参阅this answer和这两个MSDN页面:
答案 2 :(得分:2)
我知道它有点晚了,但我有另一个对我有用的解决方案。我为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>
成了
<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>
答案 3 :(得分:2)
实现此目的的另一种方法是创建您自己的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);
}
}