Отключить колесо мыши на элементах управления в wpf
У меня есть usercontrol, у которого есть scrollviewer, тогда в нем есть набор дочерних элементов управления, таких как текстовые поля, переключатели и список, и т.д. Я могу использовать колесико мыши для прокрутки родительского scrollviewer до тех пор, пока моя мышь не приземлится внутри списка, а события колеса мыши начнут поступать в список. есть ли способ, чтобы список пересылал эти события обратно в родительский элемент управления? удалив список изнутри, родительский элемент управления, как этот вопрос предлагает (Колесо мыши не работает, когда над дочерними элементами ScrollViewer) не является решением.
Я пробовал
void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
}
но это тоже не работает.
Спасибо
Ответы
Ответ 1
Ответ, на который вы ссылаетесь, является именно тем, что вызывает вашу проблему, ListBox (который состоит из прочего ScrollViewer) внутри вашего ScrollViewer ловит событие MouseWheel и обрабатывает его, не позволяя ему кипеть, и, следовательно, ScrollViewer не имеет Идея события когда-либо происходила.
Используйте демонстрационный пример для элемента управления ListBox (обратите внимание, что в нем нет ScrollViewer, и поэтому событие MouseWheel не будет обнаружено). ScrollViewer по-прежнему будет прокручиваться с помощью мыши над 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>
У вас есть возможность захвата мыши, когда она входит в ScrollViewer, хотя она продолжает получать все события мыши до тех пор, пока мышь не будет выпущена, однако эта опция потребует, чтобы вы отклонили любые другие события мыши на элементы управления, содержащиеся в ScrollViewer, если вы хотите получить ответ... следующие обработчики событий MouseEnter MouseLeave будут достаточными.
private void ScrollViewerMouseEnter(object sender, MouseEventArgs e)
{
((ScrollViewer)sender).CaptureMouse();
}
private void ScrollViewerMouseLeave(object sender, MouseEventArgs e)
{
((ScrollViewer)sender).ReleaseMouseCapture();
}
Ни один из обходных решений, которые я предоставил, действительно не рекомендуется, и я бы предложил переосмыслить то, что вы на самом деле пытаетесь сделать. Если вы объясните, что вы пытаетесь достичь в своем вопросе, я уверен, что вы получите еще несколько предложений...
Ответ 2
Это может быть выполнено с помощью прикрепленных поведений.
http://josheinstein.com/blog/index.php/2010/08/wpf-nested-scrollviewer-listbox-scrolling/
Изменить:
Вот связанное решение:
"Итак, вместо этого я придумал следующее IgnoreMouseWheelBehavior. Технически это не игнорирование MouseWheel, но оно" пересылает "событие обратно и из списка ListBox. Проверьте его."
/// <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);
}
}
И вот как вы будете использовать его в XAML.
<ScrollViewer Name="IScroll">
<ListBox Name="IDont">
<i:Interaction.Behaviors>
<local:IgnoreMouseWheelBehavior />
</i:Interaction.Behaviors>
</ListBox>
</ScrollViewer>
Где пространство имен я от Blend:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Ответ 3
Я последовал за подходом Amanduh, чтобы решить ту же проблему, что и у нескольких datagrids в scrollviewer, но в 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);
}
}
Ответ 4
Как сказал Саймон, это ScrollViewer в стандартном шаблоне ListBox, который ловит событие. Чтобы обойти это, вы можете предоставить свой собственный шаблон.
<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>
И реализация для NoWheelScrollViewer довольно проста.
public class NoWheelScrollViewer : ScrollViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
// Do nothing
}
}
Затем, когда вы хотите, чтобы listbox не обрабатывал колесо мыши.
<ListBox Template="{StaticResource NoWheelScrollListBoxTemplate}">
Ответ 5
Простое решение, которое сработало для меня, - это переопределить внутренний шаблон управления, чтобы удалить средство просмотра прокрутки (в зависимости от того, что требуется)
Например
У меня есть такая структура
Мне захотелось прокрутить прокрутку колесика мыши (b) до (a), однако захотелось сохранить прокрутку колесика мыши (c).
Я просто переопределил шаблон (b), как это. Это позволило мне пузырить содержимое (б), за исключением (с) - (а). Кроме того, я все еще могу прокрутить содержимое (c). Если я хочу удалить даже для (c), тогда я должен повторить тот же шаг.
<ListView.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListView.Template>
Ответ 6
Я пытался адаптировать Simon Fox ответ для DataGrid. Я обнаружил, что шаблон спрятал мои заголовки, и я никогда не получал событие mouseLeave, выполняя его на С#. В конечном итоге это помогло мне:
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
((DataGrid)sender).CaptureMouse();
}
private void DataGrid_MouseWheel(object sender, MouseWheelEventArgs e)
{
((DataGrid)sender).ReleaseMouseCapture();
}
Ответ 7
Измененное решение Simon Fox, если оригинал не работает:
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;
}
}
Ответ 8
Вы должны прослушивать PreviewMouseWheel из ScrollViewer (он работает), но не из списка.