2010-05-26 8 views

Respuesta

17

La forma más sencilla es la subclase deslizante:

public class CustomSlider : Slider 
{ 
    public override void OnPreviewMouseMove(MouseEventArgs e) 
    { 
    if(e.LeftButton == MouseButtonState.Pressed) 
     OnPreviewMouseLeftButtonDown(e); 
    } 
} 

En cuyo caso su XAML sería:

<my:CustomSlider IsMoveToPointEnabled="True" /> 

Para una solución más versátil que no subclase deslizante que puede hacerlo con una propiedad adjunta:

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, 
      }); 
     }; 
    } 
    }); 
} 

Utilizaría esta propiedad adjunta en el control deslizante junto con el IsMov eToPointEnabled propiedad:

<Slider IsMoveToPointEnabled="True" my:SliderTools.MoveToPointOnDrag="True" ... /> 

Ambas soluciones de trabajo mediante la conversión de los eventos en los eventos PreviewMouseMove PreviewMouseLeftButtonDown equivalentes siempre que el botón izquierdo está abajo.

Tenga en cuenta que la propiedad adjunta no elimina el controlador de eventos cuando la propiedad se establece en falso. Lo escribí de esta manera por simplicidad, ya que casi nunca necesitarías eliminar dicho controlador. Le recomiendo que se quede con esta solución simple, pero si lo desea, puede modificar PropertyChangedCallback para eliminar el controlador cuando NewValue sea falso.

+0

Gracias Ray! Creo que casi lo tengo funcionando. Tengo un problema con el tipo de conversión en la función de movimiento del mouse en SliderTools. Aquí está mi error: No se puede convertir objeto de tipo 'System.Windows.Input.MouseButtonEventHandler' al tipo 'System.Windows.Input.MouseEventHandler'. ¿Alguna idea sobre cómo solucionarlo? –

+1

Perdón por eso. Para la técnica de evento enrutado, necesitaba pasar un MouseButtonEventArgs en lugar de un MouseEventArgs porque MouseEventArgs en realidad comprueba su tipo de evento. Realicé el cambio necesario y probé el código resultante. Parece hacer exactamente lo que quieres. ¡Disfrutar! –

0

¿Qué tal

private void slider_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
    { 
     Point point = e.GetPosition(slider); 
     slider.Value = point.X; 
    } 
5

Inspirado por Ray quemaduras respuesta, la forma más sencilla que he encontrado es la siguiente:

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 
     }); 
    } 
}; 

Con mySlider ser el nombre de mi Slider.

Hay dos problemas con esta solución (y la mayoría de los demás en este tema):
1. Si hace clic y mantiene el mouse fuera del control deslizante y lo mueve en el control deslizante, se iniciará la acción de arrastre.
2. Si está utilizando la sugerencia de autolín del control deslizante, no funcionará mientras arrastra con este método.

Así que aquí es una versión mejorada, que fuerza a ambos problemas:

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 es una variable auxiliar privado definido somwhere en la clase.

Al usar la variable de ayuda clickedInSlider evitamos 1. Se maneja el evento PreviewMouseButtonDown (debido a MoveToPoint = true), por lo que tenemos que usar mySlider.AddHandler.
Al mostrar el evento en el pulgar en lugar del control deslizante, nos aseguramos de que aparece la sugerencia de autotool.

+0

Mejor versión que he encontrado hasta ahora para un control deslizante mejorado. Lo uso para crear un control deslizante más táctil. Sin embargo, me pareció más limpio implementarlo en una subclase. ¡Gracias! – monoceres

0
  1. Necesita control deslizante personalizado y pulgar personalizado.Al hacer clic en el control deslizante (no un golpe en el pulgar) -

    var hitTestResult = VisualTreeHelper.HitTest(this, point); 
    if (hitTestResult == null) return; 
    var parent = hitTestResult.VisualHit.ParentOfType<Thumb>(); 
    if (parent != null) return; 
    _customThumb.OnMouseLeftButtonDown(e); 
    

puede llamar en el método deslizador personalizada, que llame dentro OnMouseLeftButtonDown(MouseButtonEventArgs e)

  1. Puede usted standart Thumb y use Reflaction para llamar a OnMouseLeftButtonDown(MouseButtonEventArgs e)
1

Aquí está la versión mejorada de la respuesta de @ TimPohlmann.

éste plantea MouseButtonEventHandler sólo una vez. aunque el pulgar aumenta DragDeltaEventHandler internamente en cada movimiento del mouse. pero me pareció innecesario disparar MouseLeftButtonDownEvent en el pulgar en cada movimiento del mouse yo mismo.

Además, no hay necesidad de que la variable auxiliar.

Esto se implementa como un comportamiento. AssociatedObject es el control deslizante al que se asocia este comportamiento.

XAML:

<Slider ...> 
    <i:Interaction.Behaviors> 
     <slid:FreeSlideBehavior /> 
    </i:Interaction.Behaviors> 
</Slider> 

Comportamiento:

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 
     }); 
    } 
} 
+0

Tenga en cuenta que necesita agregar el ensamblado "Interactividad" para que esto funcione, que no está incluido por defecto. –

+0

Además, al parecer utilizando Comportamiento rompe el diseñador (https://connect.microsoft.com/VisualStudio/feedback/details/755407/xaml-designer-will-not-display-when-using-blend-sdk-behaviors, https: //catelproject.atlassian.net/browse/CTL-765). Creo que lo evitaré ... –

Cuestiones relacionadas