У меня есть IsMoveToPointEnabled для моего слайдера, поэтому, когда я нажимаю в любом месте компонента, селектор перемещается к моей мыши. Проблема в том, что если у меня есть эта опция и нажмите и удерживайте мышь, чтобы перетащить селектор, селектор не перемещается. Кто-нибудь знает, как это исправить?
Ползунок не перетаскивается в сочетании с поведением IsMoveToPointEnabled
Ответ 1
Самый простой способ - подкласс Slider:
public class CustomSlider : Slider
{
public override void OnPreviewMouseMove(MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed)
OnPreviewMouseLeftButtonDown(e);
}
}
В этом случае ваш XAML будет:
<my:CustomSlider IsMoveToPointEnabled="True" />
Для более универсального решения, которое не является подклассом Slider, вы можете сделать это с прикрепленным свойством:
public class SliderTools : DependencyObject
{
public static bool GetMoveToPointOnDrag(DependencyObject obj) { return (bool)obj.GetValue(MoveToPointOnDragProperty); }
public static void SetMoveToPointOnDrag(DependencyObject obj, bool value) { obj.SetValue(MoveToPointOnDragProperty, value); }
public static readonly DependencyProperty MoveToPointOnDragProperty = DependencyProperty.RegisterAttached("MoveToPointOnDrag", typeof(bool), typeof(SliderTools), new PropertyMetadata
{
PropertyChangedCallback = (obj, changeEvent) =>
{
var slider = (Slider)obj;
if((bool)changeEvent.NewValue)
slider.MouseMove += (obj2, mouseEvent) =>
{
if(mouseEvent.LeftButton == MouseButtonState.Pressed)
slider.RaiseEvent(new MouseButtonEventArgs(mouseEvent.MouseDevice, mouseEvent.Timestamp, MouseButton.Left)
{
RoutedEvent = UIElement.PreviewMouseLeftButtonDownEvent,
Source = mouseEvent.Source,
});
};
}
});
}
Вы использовали бы это вложенное свойство в Slider вместе со свойством IsMoveToPointEnabled:
<Slider IsMoveToPointEnabled="True" my:SliderTools.MoveToPointOnDrag="True" ... />
Оба этих решения работают путем преобразования событий PreviewMouseMove в эквивалентные события PreviewMouseLeftButtonDown всякий раз, когда левая кнопка не работает.
Обратите внимание, что вложенное свойство не удаляет обработчик события, если для свойства установлено значение false. Я написал это для простоты, так как вам почти никогда не нужно было удалять такой обработчик. Я рекомендую вам придерживаться этого простого решения, но если вы хотите, вы можете изменить PropertyChangedCallback, чтобы удалить обработчик, когда NewValue является ложным.
Ответ 2
Вдохновленный Ray Burns Ответ, самый простой способ, который я нашел, заключается в следующем:
mySlider.PreviewMouseMove += (sender, args) =>
{
if (args.LeftButton == MouseButtonState.Pressed)
{
mySlider.RaiseEvent(new MouseButtonEventArgs(args.MouseDevice, args.Timestamp, MouseButton.Left)
{
RoutedEvent = UIElement.PreviewMouseLeftButtonDownEvent,
Source = args.Source
});
}
};
Когда mySlider является именем моего слайдера.
Есть два вопроса с этим решением (и большинство других в этом разделе):
1. Если вы нажмете и удерживаете мышь за пределами ползунка, а затем переместите ее на ползунок, начнется перетаскивание.
2. Если вы используете автотекст ползунка, он не будет работать при перетаскивании с помощью этого метода.
Итак, вот улучшенная версия, которая решает обе проблемы:
mySlider.MouseMove += (sender, args) =>
{
if (args.LeftButton == MouseButtonState.Pressed && this.clickedInSlider)
{
var thumb = (mySlider.Template.FindName("PART_Track", mySlider) as System.Windows.Controls.Primitives.Track).Thumb;
thumb.RaiseEvent(new MouseButtonEventArgs(args.MouseDevice, args.Timestamp, MouseButton.Left)
{
RoutedEvent = UIElement.MouseLeftButtonDownEvent,
Source = args.Source
});
}
};
mySlider.AddHandler(UIElement.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler((sender, args) =>
{
clickedInSlider = true;
}), true);
mySlider.AddHandler(UIElement.PreviewMouseLeftButtonUpEvent, new RoutedEventHandler((sender, args) =>
{
clickedInSlider = false;
}), true);
clickedInSlider - это частная вспомогательная переменная, определенная где-то в классе.
С помощью хелперной переменной clickedInSlider мы избегаем 1. Событие PreviewMouseButtonDown обрабатывается (из-за MoveToPoint = true), поэтому мы должны использовать mySlider.AddHandler.
Подняв событие на Thumb вместо Slider, мы гарантируем, что появится autotooltip.
Ответ 3
Вот улучшенная версия ответа @TimPohlmann.
этот воскрешает MouseButtonEventHandler
только один раз. хотя большой палец поднимает DragDeltaEventHandler
внутри каждого движения мыши. но я не счел нужным стрелять MouseLeftButtonDownEvent
на большой палец на каждом шаге мыши.
Также нет необходимости в вспомогательной переменной.
Это реализовано как поведение. AssociatedObject
- это слайдер, к которому это поведение привязано.
XAML:
<Slider ...>
<i:Interaction.Behaviors>
<slid:FreeSlideBehavior />
</i:Interaction.Behaviors>
</Slider>
Поведение:
public sealed class FreeSlideBehavior : Behavior<Slider>
{
private Thumb _thumb;
private Thumb Thumb
{
get
{
if (_thumb == null)
{
_thumb = ((Track)AssociatedObject.Template.FindName("PART_Track", AssociatedObject)).Thumb;
}
return _thumb;
}
}
protected override void OnAttached()
{
AssociatedObject.MouseMove += OnMouseMove;
}
protected override void OnDetaching()
{
AssociatedObject.MouseMove -= OnMouseMove;
}
private void OnMouseMove(object sender, MouseEventArgs args)
{
if (args.LeftButton == MouseButtonState.Released) return;
if(Thumb.IsDragging) return;
if (!Thumb.IsMouseOver) return;
Thumb.RaiseEvent(new MouseButtonEventArgs(args.MouseDevice, args.Timestamp, MouseButton.Left)
{
RoutedEvent = UIElement.MouseLeftButtonDownEvent
});
}
}
Ответ 4
Как насчет
private void slider_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Point point = e.GetPosition(slider);
slider.Value = point.X;
}
Ответ 5
-
Вам нужен пользовательский слайдер и пользовательский палец. Когда вы нажимаете ползунок (не попадаете большим пальцем) -
var hitTestResult = VisualTreeHelper.HitTest(this, point); if (hitTestResult == null) return; var parent = hitTestResult.VisualHit.ParentOfType<Thumb>(); if (parent != null) return; _customThumb.OnMouseLeftButtonDown(e);
вы можете вызвать пользовательский метод слайдера, который вызывает внутри OnMouseLeftButtonDown(MouseButtonEventArgs e)
- Вы можете использовать стандартный Thumb и использовать Reflaction для вызова
OnMouseLeftButtonDown(MouseButtonEventArgs e)