WPF 拖动实现
在WPF中实现控件的拖动很多是是用thumb控件,今天学习到了一种新的方式,采用Behavior 实现了控件的拖动及位置限制
效果展示
代码如下
/// <summary> /// 拖动辅助类 /// </summary> public class DragMoveBehavior : Behavior<FrameworkElement> { #region Property public static readonly DependencyProperty MaxHProperty = DependencyProperty.Register("MaxH", typeof(double), typeof(DragMoveBehavior), new PropertyMetadata(0d, OnMaxHChanged)); public static readonly DependencyProperty MaxWProperty = DependencyProperty.Register("MaxW", typeof(double), typeof(DragMoveBehavior), new PropertyMetadata(0d, OnMaxWChanged)); /// <summary> /// max w /// </summary> public double MaxW { get { return (double)GetValue(MaxWProperty); } set { SetValue(MaxWProperty, value); } } /// <summary> /// max h /// </summary> public double MaxH { get { return (double)GetValue(MaxHProperty); } set { SetValue(MaxHProperty, value); } } public double H { get { return AssociatedObject.Height; } } public double W { get { return AssociatedObject.Width; } } private Transform RenderTransform { get { return AssociatedObject.RenderTransform; } set { AssociatedObject.RenderTransform = value; } } private Point _mousePoint; #endregion private static void OnMaxHChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var behavior = (DragMoveBehavior)d; behavior.MaxH = (double)e.NewValue; } private static void OnMaxWChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var behavior = (DragMoveBehavior)d; behavior.MaxW = (double)e.NewValue; } protected override void OnAttached() { AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown), false); UpdatePosition(new Point(RenderTransform.Value.OffsetX, RenderTransform.Value.OffsetY)); } protected override void OnDetaching() { AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown)); } private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { _mousePoint = e.GetPosition(null); AssociatedObject.CaptureMouse(); AssociatedObject.MouseMove += OnMouseMove; AssociatedObject.LostMouseCapture += OnLostMouseCapture; AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUp), false); } private void OnMouseMove(object sender, MouseEventArgs e) { //移动鼠标后新的位置 var newPoint = e.GetPosition(null); //本次移动的偏移量 var offset = newPoint - _mousePoint; //保存当前鼠标位置 _mousePoint = newPoint; //更新位置 ApplyTranslation(RenderTransform.Value.OffsetX + offset.X, RenderTransform.Value.OffsetY + offset.Y); } private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { AssociatedObject.ReleaseMouseCapture(); } private void OnLostMouseCapture(object sender, MouseEventArgs e) { AssociatedObject.MouseMove -= OnMouseMove; AssociatedObject.LostMouseCapture -= OnLostMouseCapture; AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUp)); } /// <summary> /// 尝试更新位置 /// </summary> /// <param name="point"></param> private void UpdatePosition(Point point) { if (AssociatedObject == null) return; ApplyTranslation(point.X, point.Y); } /// <summary> /// 更新平移转换 /// </summary> /// <param name="x"></param> /// <param name="y"></param> private void ApplyTranslation(double x, double y) { var transfromGroup = RenderTransform as TransformGroup; if (transfromGroup == null || transfromGroup.Children.FirstOrDefault(o => (o.GetType() == typeof(TranslateTransform)) ) == default(TranslateTransform)) { var rt = new TransformGroup { Children = new TransformCollection() { new TranslateTransform(x, y) } }; return; } if (x < 0) { x = 0; } else if (x > MaxW - W) { x = MaxW - W; } if (y < 0) { y = 0; } else if (y > MaxH - H) { y = MaxH - H; } TranslateTransform translateTransform = (TranslateTransform)transfromGroup.Children.First(o => o.GetType() == typeof(TranslateTransform)); translateTransform.X = x; translateTransform.Y = y; } }
页面设置代码如下
<Window x:Class="DragMoveDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behavior="clr-namespace:DragMoveDemo" Title="MainWindow" Height="450" Width="625"> <Canvas Height="330" Width="525" Background="Yellow"> <TextBox x:Name="xpoint" Canvas.Left="35" Canvas.Top="-32" Width="85" Text="34"></TextBox> <TextBox x:Name="ypoint" Canvas.Left="305" Canvas.Top="-32" Width="75" Text="44" RenderTransformOrigin="1,0.412"></TextBox> <Rectangle Width="90" Height="80" Fill="Red" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform X="{Binding ElementName=xpoint, Path=Text,Mode=TwoWay}" Y="{Binding ElementName=ypoint,Path=Text,Mode=TwoWay}"/> </TransformGroup> </Rectangle.RenderTransform> <i:Interaction.Behaviors> <behavior:DragMoveBehavior MaxH="330" MaxW="525" /> </i:Interaction.Behaviors> </Rectangle> </Canvas> </Window>