WPF Circle Rotate via MouseDown MouseMove and MouseUp, and compute rotated angle via Vector
<Window x:Class="WpfApp158.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp158" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <local:SizeConverter x:Key="sizeConverter"/> </Window.Resources> <Grid> <Ellipse x:Name="elp" Width="{Binding ActualHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}, Converter={StaticResource sizeConverter}}" Height="{Binding ActualHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}, Converter={StaticResource sizeConverter}}" MouseDown="elp_MouseDown" MouseMove="elp_MouseMove" MouseUp="elp_MouseUp" RenderTransformOrigin="0.5,0.5" > <Ellipse.RenderTransform> <RotateTransform x:Name="rotateTransform"/> </Ellipse.RenderTransform> <Ellipse.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="Orange" Offset="0.0"/> <GradientStop Color="Orange" Offset="0.2"/> <GradientStop Color="Yellow" Offset="0.2"/> <GradientStop Color="Yellow" Offset="0.4"/> <GradientStop Color="Green" Offset="0.4"/> <GradientStop Color="Green" Offset="0.499"/> <GradientStop Color="Red" Offset="0.499"/> <GradientStop Color="Red" Offset="0.501"/> <GradientStop Color="Green" Offset="0.501"/> <GradientStop Color="Green" Offset="0.6"/> <GradientStop Color="Cyan" Offset="0.6"/> <GradientStop Color="Cyan" Offset="0.8"/> <GradientStop Color="Blue" Offset="0.8"/> <GradientStop Color="Blue" Offset="1.0"/> </LinearGradientBrush> </Ellipse.Fill> </Ellipse> </Grid> </Window> //cs using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Diagnostics; using System.Globalization; namespace WpfApp158 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private Point prevPt { get; set; } private Point originPt { get; set; } public MainWindow() { InitializeComponent(); } protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { base.OnRenderSizeChanged(sizeInfo); Point tempPt = new Point(elp.ActualWidth / 2, elp.ActualHeight / 2); originPt = elp.TranslatePoint(tempPt, this); Debug.WriteLine($"{originPt.X},{originPt.Y}"); } private void elp_MouseDown(object sender, MouseButtonEventArgs e) { if(e.LeftButton==MouseButtonState.Pressed) { prevPt = e.GetPosition(this); elp.CaptureMouse(); } } private void elp_MouseMove(object sender, MouseEventArgs e) { if(e.LeftButton==MouseButtonState.Pressed) { Vector prevVec=Point.Subtract(prevPt, originPt); Point pt=e.GetPosition(this); Vector nowVec=Point.Subtract(pt, originPt); double deltaAngle= Vector.AngleBetween(prevVec, nowVec); Console.WriteLine($"deltaAngle:{deltaAngle}"); rotateTransform.Angle += deltaAngle; this.Title=Math.Round(rotateTransform.Angle,2).ToString(); prevPt = pt; Debug.WriteLine(rotateTransform.Angle.ToString()); } } private void elp_MouseUp(object sender, MouseButtonEventArgs e) { if( e.LeftButton==MouseButtonState.Released) { elp.ReleaseMouseCapture(); } } } public class SizeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double dValue = 0.0; if(double.TryParse(value?.ToString(), out dValue)) { return dValue - 100; } return dValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }