Bubbling прокручивает события из ListView в родительский

В моем приложении WPF у меня есть ListView которого ScrollViewer.VerticalScrollBarVisibility установлено значение Disabled . Он содержится в ScrollViewer . Когда я пытаюсь использовать колесо мыши над ListView , внешний ScrollViewer не прокручивается, потому что ListView захватывает события прокрутки.

Как заставить ListView разрешить событиям прокрутки ScrollViewer в ScrollViewer ?

Вам нужно захватить событие мыши для предварительного просмотра во внутреннем списке

 ctl.PreviewMouseWheel += PreviewMouseWheel; 

затем остановите событие от прокрутки списка и поднимите событие в родительском списке.

 private static void PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (!e.Handled) { e.Handled = true; var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); eventArg.RoutedEvent = UIElement.MouseWheelEvent; eventArg.Source = sender; var parent = ((Control)sender).Parent as UIElement; parent.RaiseEvent(eventArg); } } 

Кредиты идут к @ robert-wagner, которые решили это для меня несколько месяцев назад.

Еще одно приятное решение, использующее приложенное поведение. Мне нравится, потому что он отменяет решение от Control.

Создайте поведение без прокрутки, которое будет захватывать событие PreviewMouseWheel (Tunneling) и поднять новый MouseWheelEvent (Bubbling)

 public sealed class IgnoreMouseWheelBehavior : Behavior { 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); } } 

Затем присоедините поведение к любому UIElement с вложенным случаем ScrollViewers

       

все кредиты Джошу Эйнштейну Блог

Если вы придете сюда искать решение, чтобы пузырить событие ТОЛЬКО, если ребенок находится наверху и прокручивается вверх или вниз и прокручивается вниз, вот решение. Я тестировал это только с помощью DataGrid, но он должен работать и с другими элементами управления.

 public class ScrollParentWhenAtMax : Behavior { protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.PreviewMouseWheel += PreviewMouseWheel; } protected override void OnDetaching() { this.AssociatedObject.PreviewMouseWheel -= PreviewMouseWheel; base.OnDetaching(); } private void PreviewMouseWheel(object sender, MouseWheelEventArgs e) { var scrollViewer = GetVisualChild(this.AssociatedObject); var scrollPos = scrollViewer.ContentVerticalOffset; if ((scrollPos == scrollViewer.ScrollableHeight && e.Delta < 0) || (scrollPos == 0 && e.Delta > 0)) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); e2.RoutedEvent = UIElement.MouseWheelEvent; AssociatedObject.RaiseEvent(e2); } } private static T GetVisualChild(DependencyObject parent) where T : Visual { T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < numVisuals; i++) { Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); child = v as T; if (child == null) { child = GetVisualChild(v); } if (child != null) { break; } } return child; } } 

Чтобы придать этому поведению, добавьте следующие XMLNS и XAML к элементу:

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

Существуют разные подходы в зависимости от вашей конкретной ситуации, но я нашел, что это работает хорошо. Предполагая, что ваша основная ситуация такова:

         1,2,3,4,5,6,7,8,9,10             

Поднятие MouseWheelEvent себя во время PreviewMouseWheel, похоже, заставляет ScrollViewer работать. Хотелось бы, чтобы я знал, почему это кажется очень противоречивым.

 private void listTest_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; MouseWheelEventArgs e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); e2.RoutedEvent = UIElement.MouseWheelEvent; listTest.RaiseEvent(e2); } 

Мой вариант использования был несколько иным. У меня очень большой scrollviewer, а внизу – еще один scrollviewer с максимальным числом 600. Я хочу прокрутить всю страницу до нижней части, пока не прохожу прокрутки к внутреннему scrollviewer. Это гарантирует, что вы сначала увидите весь scrollviewer, прежде чем начинать прокрутку.

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interactivity; using System.Windows.Media; namespace CleverScroller.Helper { public class ScrollParentWhenAtMax : Behavior { protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.PreviewMouseWheel += PreviewMouseWheel; } protected override void OnDetaching() { this.AssociatedObject.PreviewMouseWheel -= PreviewMouseWheel; base.OnDetaching(); } private void PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (e.Delta < 0) { var outerscroller = GetVisualParent(this.AssociatedObject); if (outerscroller.ContentVerticalOffset < outerscroller.ScrollableHeight) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); e2.RoutedEvent = UIElement.MouseWheelEvent; AssociatedObject.RaiseEvent(e2); } } else { var scrollViewer = GetVisualChild(this.AssociatedObject); var scrollPos = scrollViewer.ContentVerticalOffset; if ((scrollPos == scrollViewer.ScrollableHeight && e.Delta < 0) || (scrollPos == 0 && e.Delta > 0)) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); e2.RoutedEvent = UIElement.MouseWheelEvent; AssociatedObject.RaiseEvent(e2); } } } private static T GetVisualChild(DependencyObject parent) where T : Visual { T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < numVisuals; i++) { Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); child = v as T; if (child == null) { child = GetVisualChild(v); } if (child != null) { break; } } return child; } private static T GetVisualParent(DependencyObject parent) where T : Visual { T obj = default(T); Visual v = (Visual)VisualTreeHelper.GetParent(parent); do { v = (Visual)VisualTreeHelper.GetParent(v); obj = v as T; } while (obj == null); return obj; } } } 

Прошло некоторое время, так как я был на SO, но мне пришлось прокомментировать это. Любой туннель для предварительного просмотра событий, так почему мы это пузырям? Остановите туннель в родительском доме и сделайте это. в родителе добавить событие PreviewMouseWheel.

  private void UIElement_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { var scrollViewer = FindName("LeftPanelScrollViwer"); // name your parent mine is a scrollViewer ((ScrollViewer) scrollViewer)?.ScrollToVerticalOffset(e.Delta); e.Handled = true; } 

Вы также можете добиться того же, используя приложенное поведение. Это имеет то преимущество, что не нужна библиотека System.Windows.Interactivity. Логика была взята из других ответов, только реализация отличается.

 public static class IgnoreScrollBehaviour { public static readonly DependencyProperty IgnoreScrollProperty = DependencyProperty.RegisterAttached("IgnoreScroll", typeof(bool), typeof(IgnoreScrollBehaviour), new PropertyMetadata(OnIgnoreScollChanged)); public static void SetIgnoreScroll(DependencyObject o, string value) { o.SetValue(IgnoreScrollProperty, value); } public static string GetIgnoreScroll(DependencyObject o) { return (string)o.GetValue(IgnoreScrollProperty); } private static void OnIgnoreScollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { bool ignoreScoll = (bool)e.NewValue; UIElement element = d as UIElement; if (element == null) return; if (ignoreScoll) { element.PreviewMouseWheel += Element_PreviewMouseWheel; } else { element.PreviewMouseWheel -= Element_PreviewMouseWheel; } } private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { UIElement element = sender as UIElement; if (element != null) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta); e2.RoutedEvent = UIElement.MouseWheelEvent; element.RaiseEvent(e2); } } } 

И затем в XAML:

       ...       ...   
  • Получение каталога приложения из приложения WPF
  • Как связать с паролем в MVVM
  • Bind TextBox при нажатии клавиши Enter
  • программно добавлять столбцы и строки в WPF Datagrid
  • Как связать WPF DataGrid с переменным числом столбцов?
  • В WPF, каковы различия между атрибутами x: Name и Name?
  • Можно ли выбрать текстовый блок WPF?
  • Связывание RelativeSource с помощью ToolTip или ContextMenu
  • Можете ли вы использовать поставщика членства asp.net в приложении Windows?
  • Динамически добавлять несколько кнопок в окно wpf?
  • Установка DataContext в XAML в WPF
  • Давайте будем гением компьютера.