わかりやすくするために簡略化した次の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
sは、任意の位置、サイズなどを持つTextBox
esで表すことができます。 ListBox
のスタイル付き「領域」が大きすぎて一度に表示できない場合は、水平および垂直スクロールが可能ですが、スクロールバーを使用した場合のみです。
人間工学と健全性を高めるために、マウスホイールでのスクロールが可能である必要があります。通常、ScrollViewer
が自動的に処理しますが、ListBox
が親ScrollViewer
それらを見ることはありません。これまでのところ、ホイールスクロールが機能するのはIsHitTestVisible=False
はListBox
または親Grid
のいずれかですが、その後は子要素のマウスイベントは機能しません。
ScrollViewer
がマウスホイールイベントを確実に表示し、他の要素を子要素に維持するために何ができますか?
編集:ListBox
には組み込みのScrollViewer
があり、おそらく親ScrollViewer
からホイールイベントを盗んでいること、およびコントロールテンプレートを指定すると無効にできることを知りました。それで問題が解決した場合は、この質問を更新します。
ControlTemplate
を含まないListbox
にScrollViewer
を指定すると、問題が解決します。詳細については、 この回答 およびこれら2つのMSDNページを参照してください。
ビヘイビアーを作成し、それを親コントロール(スクロールイベントがバブリングする必要がある)にアタッチすることもできます。
// 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>
これを実装する別の方法は、次のような独自の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);
}
}
私はそれが少し遅れていることを知っていますが、私のために働いた別の解決策があります。私は自分のスタックパネル/リストボックスをitemscontrol/gridに切り替えました。スクロールイベントが適切に機能する理由はわかりませんが、私の場合は機能します。
<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>