c# .net wpf listbox scrollwheel

c# - deshabilitar la rueda del mouse en itemscontrol en wpf



.net listbox (8)

Como dijo Simon, es el ScrollViewer en la plantilla estándar de ListBox que atrapa el evento. Para eludirlo, puede proporcionar su propia plantilla.

<ControlTemplate x:Key="NoWheelScrollListBoxTemplate" TargetType="ListBox"> <Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True"> <!-- This is the new control --> <l:NoWheelScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> </l:NoWheelScrollViewer> </Border> <ControlTemplate.Triggers> <Trigger Property="UIElement.IsEnabled" Value="False"> <Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> </Trigger> <Trigger Property="ItemsControl.IsGrouping" Value="True"> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>

Y la implementación de NoWheelScrollViewer es bastante simple.

public class NoWheelScrollViewer : ScrollViewer { protected override void OnMouseWheel(MouseWheelEventArgs e) { // Do nothing } }

Luego, cada vez que quiera un cuadro de lista para no manejar la rueda del mouse.

<ListBox Template="{StaticResource NoWheelScrollListBoxTemplate}">

Tengo un usercontrol que tiene un scrollviewer, luego un grupo de controles secundarios como cuadros de texto, botones de radio y listboxes, etc. dentro de él. Puedo usar la rueda del mouse para desplazar el visualizador de desplazamiento principal hasta que el mouse aterrice dentro de un cuadro de lista, luego, los eventos de la rueda del mouse comienzan a ir al cuadro de lista. ¿Hay alguna forma de que el listbox envíe esos eventos al control principal? la eliminación del cuadro de lista desde dentro del control principal, como sugiere esta pregunta (la rueda del mouse no funciona cuando está sobre los controles secundarios de ScrollViewer ) no es una solución.

Yo he tratado

void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; }

pero eso tampoco funcionó.

Gracias


Debe escuchar PreviewMouseWheel desde ScrollViewer (funciona), pero no desde listbox.


Esto se puede lograr a través de comportamientos adjuntos.

http://josheinstein.com/blog/index.php/2010/08/wpf-nested-scrollviewer-listbox-scrolling/

Editar: Aquí está la solución vinculada:

"Así que en su lugar, se me ocurrió la siguiente IgnoreMouseWheelBehavior. Técnicamente, no está ignorando la MouseWheel, pero está" reenviando "la copia de seguridad del evento fuera de ListBox. Verifíquelo".

/// <summary> /// Captures and eats MouseWheel events so that a nested ListBox does not /// prevent an outer scrollable control from scrolling. /// </summary> public sealed class IgnoreMouseWheelBehavior : 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); } }

Y así es como lo usarías en XAML.

<ScrollViewer Name="IScroll"> <ListBox Name="IDont"> <i:Interaction.Behaviors> <local:IgnoreMouseWheelBehavior /> </i:Interaction.Behaviors> </ListBox> </ScrollViewer>

Donde el espacio de nombre de i es de Blend:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"


Intentaba adaptar la respuesta de Simon Fox para un DataGrid. Encontré que la plantilla ocultaba mis encabezados, y nunca obtuve el evento mouseLeave al hacerlo en C #. Esto es, en última instancia, lo que funcionó para mí:

private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { ((DataGrid)sender).CaptureMouse(); } private void DataGrid_MouseWheel(object sender, MouseWheelEventArgs e) { ((DataGrid)sender).ReleaseMouseCapture(); }


La respuesta a la que se ha referido es exactamente lo que está causando su problema, el ListBox (que se compone entre otras cosas de un ScrollViewer) dentro de ScrollViewer capta el evento MouseWheel y lo maneja, evitando que burbujee y por lo tanto el ScrollViewer no tiene idea del evento. alguna vez ocurrió

Utilice el siguiente ControlTemplate extremadamente simple para que su ListBox lo demuestre (tenga en cuenta que no tiene un ScrollViewer en él y que el evento MouseWheel no se capturará). El ScrollViewer se desplazará aún con el mouse sobre el ListBox.

<UserControl.Resources> <ControlTemplate x:Key="NoScroll"> <ItemsPresenter></ItemsPresenter> </ControlTemplate> </UserControl.Resources> <ScrollViewer> <SomeContainerControl> <.... what ever other controls are inside your ScrollViewer> <ListBox Template="{StaticResource NoScroll}"></ListBox> <SomeContainerControl> </ScrollViewer>

Sin embargo, tiene la opción de capturar el mouse cuando ingresa al ScrollViewer, por lo que continúa recibiendo todos los eventos del mouse hasta que se suelta el mouse, sin embargo, esta opción requeriría delegar cualquier otro evento del mouse a los controles contenidos en ScrollViewer si quiere una respuesta ... los siguientes manejadores de eventos MouseEnter MouseLeave serán suficientes.

private void ScrollViewerMouseEnter(object sender, MouseEventArgs e) { ((ScrollViewer)sender).CaptureMouse(); } private void ScrollViewerMouseLeave(object sender, MouseEventArgs e) { ((ScrollViewer)sender).ReleaseMouseCapture(); }

Sin embargo, ninguna de las soluciones provisionales que he proporcionado son realmente preferidas, y sugeriría que reconsidere lo que en realidad está tratando de hacer. Si explica lo que está tratando de lograr en su pregunta, estoy seguro de que obtendrá algunas sugerencias más ...


Seguí el enfoque de Amanduh para resolver el mismo problema que tuve con múltiples datagrids en un scrollviewer pero en WPF:

public sealed class IgnoreMouseWheelBehavior { public static bool GetIgnoreMouseWheel(DataGrid gridItem) { return (bool)gridItem.GetValue(IgnoreMouseWheelProperty); } public static void SetIgnoreMouseWheel(DataGrid gridItem, bool value) { gridItem.SetValue(IgnoreMouseWheelProperty, value); } public static readonly DependencyProperty IgnoreMouseWheelProperty = DependencyProperty.RegisterAttached("IgnoreMouseWheel", typeof(bool), typeof(IgnoreMouseWheelBehavior), new UIPropertyMetadata(false, OnIgnoreMouseWheelChanged)); static void OnIgnoreMouseWheelChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { var item = depObj as DataGrid; if (item == null) return; if (e.NewValue is bool == false) return; if ((bool)e.NewValue) item.PreviewMouseWheel += OnPreviewMouseWheel; else item.PreviewMouseWheel -= OnPreviewMouseWheel; } static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) {RoutedEvent = UIElement.MouseWheelEvent}; var gv = sender as DataGrid; if (gv != null) gv.RaiseEvent(e2); } }


Una solución modificada de Simon Fox si el original no funciona:

public sealed class IgnoreMouseWheelBehavior : Behavior<UIElement> { protected override void OnAttached() { base.OnAttached(); AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel; } protected override void OnDetaching() { AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel; base.OnDetaching(); } static void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (!(sender is DependencyObject)) { return; } DependencyObject parent = VisualTreeHelper.GetParent((DependencyObject) sender); if (!(parent is UIElement)) { return; } ((UIElement) parent).RaiseEvent( new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) { RoutedEvent = UIElement.MouseWheelEvent }); e.Handled = true; } }


Una solución simple que funcionó para mí es anular la plantilla de control interno para eliminar el visor de desplazamiento (lo que sea necesario) como este

Por ejemplo, tengo una estructura como esta

  • ListView (a)

    • ListView (b)

      • ListView (c)

Quería hacer que la rueda del mouse se desplazara de (b) a (a), sin embargo, quería mantener el desplazamiento de la rueda del mouse de (c) disponible. Simplemente anulo la Plantilla de (b) de esta manera. Esto me permitió burbujear el contenido de (b) excepto (c) a (a). Además, aún puedo desplazar el contenido de (c). Si quiero eliminar incluso para (c), entonces tengo que repetir el mismo paso.

<ListView.Template> <ControlTemplate> <ItemsPresenter /> </ControlTemplate> </ListView.Template>