wpf - ¿Elementos secundarios del scrollviewer que impiden el desplazamiento con la rueda del ratón?
event-handling listbox (4)
Especificar una Listbox
para el Listbox
que no incluye un ScrollViewer
resuelve el problema. Vea esta respuesta y estas dos páginas de MSDN para obtener más información:
Tengo problemas para que la rueda del mouse funcione en el siguiente XAML, que he simplificado para mayor claridad:
<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>
Visualmente, el resultado es un área de algún tamaño conocido en el que la lectura de DataField
de una colección se puede representar con TextBox
que tienen una posición, un tamaño, etc., arbitrarios. En los casos en que el "área" con estilo de ListBox
es demasiado grande para mostrarlo todo a la vez, es posible el desplazamiento horizontal y vertical, pero solo con las barras de desplazamiento.
Para una mejor ergonomía y cordura, el desplazamiento de la rueda del mouse debería ser posible, y normalmente ScrollViewer
lo manejaría automáticamente, pero el ListBox
parece estar entregando esos eventos de tal manera que ScrollViewer
principal nunca los ve. Hasta ahora solo he podido obtener el desplazamiento de la rueda trabajando con IsHitTestVisible=False
para ListBox
o la Grid
principal, pero, por supuesto, ninguno de los eventos del ratón del elemento secundario funciona después de eso.
¿Qué puedo hacer para asegurarme de que el ScrollViewer
vea los eventos de la rueda del mouse y conserve los demás para los elementos secundarios?
Edición: Me acabo de ListBox
que ListBox
tiene un ScrollViewer
incorporado que probablemente está robando eventos de la rueda del ScrollViewer
principal y que la especificación de una plantilla de control puede desactivarlo. Voy a actualizar esta pregunta si eso resuelve el problema.
Otra forma de implementar esto, es creando su propio ScrollViewer de esta manera:
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);
}
}
Sé que es un poco tarde pero tengo otra solución que funcionó para mí. Cambié mi stackpanel / listbox para un itemscontrol / grid. No estoy seguro de por qué los eventos de desplazamiento funcionan correctamente, pero lo hacen en mi caso.
<ScrollViewer VerticalScrollBarVisibility="Auto" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
<StackPanel Orientation="Vertical">
<ListBox ItemsSource="{Binding DrillingConfigs}" Margin="0,5,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
convirtió
<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>
También puede crear un comportamiento y adjuntarlo al control principal (en el que los eventos de desplazamiento deberían crecer).
// 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>