Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Code may be a little ugly...but it works, wish this will help you, any problem just leave a comment.</p> <p>There are two point you need take care. 1, WPF do not support string propertyPath when you try to binding attached DP to an element, you can use new PropertyPath(Canvas.TopProperty) instead of "Canvas.Top", but in your scenario, we need center position of thumb, so you cann't binding this property directly. 2, since we use our custom DP, we need update this property when animation start(AddValueChanged statement).</p> <pre><code>namespace WpfApplicationThumbDrag { public class MyThumb : Thumb { public override void OnApplyTemplate() { base.OnApplyTemplate(); this.DragDelta += thumb_DragDelta; this.DragCompleted += new DragCompletedEventHandler(MyThumb_DragCompleted); this.Loaded += (s, e) =&gt; { UpdateCenter(); }; var left = DependencyPropertyDescriptor.FromProperty(Canvas.LeftProperty, typeof(Canvas)); var right = DependencyPropertyDescriptor.FromProperty(Canvas.RightProperty, typeof(Canvas)); left.AddValueChanged(this, OnCanvasLeftRightChanged); right.AddValueChanged(this, OnCanvasLeftRightChanged); } private void OnCanvasLeftRightChanged(object sender, EventArgs e) { UpdateCenter(); } private void MyThumb_DragCompleted(object sender, DragCompletedEventArgs e) { var thumb = e.Source as MyThumb; double x1 = Canvas.GetLeft(thumb) - e.HorizontalChange; double y1 = Canvas.GetTop(thumb) - e.VerticalChange; double x2 = Canvas.GetLeft(thumb); double y2 = Canvas.GetTop(thumb); AnimateThis4(x1, x2, y1, y2, thumb); } private void AnimateThis4(double x1, double x2, double y1, double y2, MyThumb thumb) { // Create a duration of 2 seconds. Duration duration = new Duration(TimeSpan.FromSeconds(2)); // Create two DoubleAnimations and set their properties. DoubleAnimation myDoubleAnimation1 = new DoubleAnimation(); DoubleAnimation myDoubleAnimation2 = new DoubleAnimation(); myDoubleAnimation1.Duration = duration; myDoubleAnimation2.Duration = duration; myDoubleAnimation1.FillBehavior = FillBehavior.Stop; myDoubleAnimation2.FillBehavior = FillBehavior.Stop; ElasticEase ea = new ElasticEase(); ea.EasingMode = EasingMode.EaseOut; ea.Springiness = 2; ea.Oscillations = 5; myDoubleAnimation1.EasingFunction = ea; myDoubleAnimation2.EasingFunction = ea; Storyboard sb = new Storyboard(); sb.Duration = duration; sb.Children.Add(myDoubleAnimation1); sb.Children.Add(myDoubleAnimation2); Storyboard.SetTarget(myDoubleAnimation1, thumb); Storyboard.SetTarget(myDoubleAnimation2, thumb); Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath("(Canvas.Left)")); Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath("(Canvas.Top)")); //Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath(TranslateTransform.XProperty)); //Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath(TranslateTransform.YProperty)); myDoubleAnimation1.From = x2; myDoubleAnimation2.From = y2; myDoubleAnimation1.To = x1; myDoubleAnimation2.To = y1; myDoubleAnimation1.Completed += new EventHandler((sender, e) =&gt; da_Completed(sender, e, x1, y1, thumb)); myDoubleAnimation2.Completed += new EventHandler((sender, e) =&gt; da_Completed(sender, e, x1, y1, thumb)); // Begin the animation. sb.Begin(); } // AFTER ANIMATION IS OVER, SET THE THUMB POSITION TO ORIGINAL void da_Completed(object sender, EventArgs e, double X, double Y, MyThumb thumb) { Canvas.SetLeft(thumb, X); Canvas.SetTop(thumb, Y); } public Point Center { get { return (Point)GetValue(CenterProperty); } set { SetValue(CenterProperty, value); } } public static readonly DependencyProperty CenterProperty = DependencyProperty.Register("Center", typeof(Point), typeof(MyThumb), new UIPropertyMetadata(new Point())); private void thumb_DragDelta(object sender, DragDeltaEventArgs e) { var left = Canvas.GetLeft(this) + e.HorizontalChange; var top = Canvas.GetTop(this) + e.VerticalChange; Canvas.SetLeft(this, left); Canvas.SetTop(this, top); } private void UpdateCenter() { var p = new Point(); p.X = Canvas.GetLeft(this) + this.ActualWidth / 2; p.Y = Canvas.GetTop(this) + this.ActualHeight / 2; this.Center = p; } } /// &lt;summary&gt; /// Interaction logic for MainWindow.xaml /// &lt;/summary&gt; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnJoinLine_Click(object sender, RoutedEventArgs e) { var line = new Line(); myCanvas.Children.Add(line); line.Stroke = Brushes.Red; line.StrokeThickness = 2; line.X1 = Canvas.GetLeft(myThumb2) + myThumb2.ActualWidth / 2; line.Y1 = Canvas.GetTop(myThumb2) + myThumb2.ActualHeight / 2; line.X2 = Canvas.GetLeft(myThumb1) + myThumb1.ActualWidth / 2; line.Y2 = Canvas.GetTop(myThumb1) + myThumb1.ActualHeight / 2; //Binding Line start X var binding1 = new Binding(); binding1.ElementName = "myThumb1"; binding1.Path = new PropertyPath("Center.X"); BindingOperations.SetBinding(line, Line.X1Property, binding1); //Binding Line start Y var binding11 = new Binding(); binding11.ElementName = "myThumb1"; binding11.Path = new PropertyPath("Center.Y"); BindingOperations.SetBinding(line, Line.Y1Property, binding11); //Binding Line end X var binding2 = new Binding(); binding2.ElementName = "myThumb2"; binding2.Path = new PropertyPath("Center.X"); BindingOperations.SetBinding(line, Line.X2Property, binding2); //Binding Line end Y var binding22 = new Binding(); binding22.ElementName = "myThumb2"; binding22.Path = new PropertyPath("Center.Y"); BindingOperations.SetBinding(line, Line.Y2Property, binding22); } } } &lt;Window x:Class="WpfApplicationThumbDrag.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplicationThumbDrag" Title="MainWindow" Width="525" Height="350"&gt; &lt;Canvas x:Name="myCanvas"&gt; &lt;local:MyThumb x:Name="myThumb1" Canvas.Left="250" Canvas.Top="70" Width="100" Height="30" /&gt; &lt;local:MyThumb x:Name="myThumb2" Canvas.Left="50" Canvas.Top="70" Width="100" Height="30" /&gt; &lt;Button x:Name="btnJoinLine" HorizontalAlignment="Right" VerticalAlignment="Top" Click="btnJoinLine_Click" Content="join" /&gt; &lt;/Canvas&gt; &lt;/Window&gt; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload