WPF usercontrol rotate circle via mousemove
//usercontrol.xaml <UserControl x:Class="WpfApp190.RotatedCircle" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp190" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Ellipse x:Name="elp" MouseDown="Ellipse_MouseDown" MouseMove="Ellipse_MouseMove" MouseUp="Ellipse_MouseUp" Width="{Binding UCElpWidth,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="{Binding UCElpHeight,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" RenderTransformOrigin="0.5,0.5"> <Ellipse.Fill> <ImageBrush ImageSource="{Binding UCImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> </Ellipse.Fill> <Ellipse.RenderTransform> <RotateTransform x:Name="elpRotate"/> </Ellipse.RenderTransform> </Ellipse> </Grid> </UserControl> //usercontrol.xaml.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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.IO; namespace WpfApp190 { /// <summary> /// Interaction logic for RotatedCircle.xaml /// </summary> public partial class RotatedCircle : UserControl { public RotatedCircle() { InitializeComponent(); this.DataContext = this; this.Loaded += RotatedCircle_Loaded; this.SizeChanged += RotatedCircle_SizeChanged; } private void RotatedCircle_SizeChanged(object sender, SizeChangedEventArgs e) { Init(); } private void RotatedCircle_Loaded(object sender, RoutedEventArgs e) { Init(); } private void Init() { var ucContent = this.Content as FrameworkElement; if (ucContent!=null) { UCElpWidth = ucContent.ActualHeight; UCElpHeight= ucContent.ActualHeight; originPt=new Point(ucContent.ActualWidth/2, ucContent.ActualHeight/2); } } public double UCElpWidth { get { return (double)GetValue(UCElpWidthProperty); } set { SetValue(UCElpWidthProperty, value); } } // Using a DependencyProperty as the backing store for UCElpWidth. This enables animation, styling, binding, etc... public static readonly DependencyProperty UCElpWidthProperty = DependencyProperty.Register("UCElpWidth", typeof(double), typeof(RotatedCircle), new PropertyMetadata(0.0d)); public double UCElpHeight { get { return (double)GetValue(UCElpHeightProperty); } set { SetValue(UCElpHeightProperty, value); } } // Using a DependencyProperty as the backing store for UCElpHeight. This enables animation, styling, binding, etc... public static readonly DependencyProperty UCElpHeightProperty = DependencyProperty.Register("UCElpHeight", typeof(double), typeof(RotatedCircle), new PropertyMetadata(0.0d)); public ImageSource UCImgSource { get { return (ImageSource)GetValue(UCImgSourceProperty); } set { SetValue(UCImgSourceProperty, value); } } // Using a DependencyProperty as the backing store for UCImgSource. This enables animation, styling, binding, etc... public static readonly DependencyProperty UCImgSourceProperty = DependencyProperty.Register("UCImgSource", typeof(ImageSource), typeof(RotatedCircle), new PropertyMetadata(GetDefaultImageSource())); public double UCElpAngle { get { return (double)GetValue(UCElpAngleProperty); } set { SetValue(UCElpAngleProperty, value); } } // Using a DependencyProperty as the backing store for UCElpAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty UCElpAngleProperty = DependencyProperty.Register("UCElpAngle", typeof(double), typeof(RotatedCircle), new PropertyMetadata(0.0d)); private static object GetDefaultImageSource() { string imgFile = @"../../Images/1.jpg"; if (!File.Exists(imgFile)) { return null; } BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.UriSource=new Uri(imgFile,UriKind.RelativeOrAbsolute); bmi.EndInit(); if(bmi.CanFreeze) { bmi.Freeze(); } return bmi; } private Point prevPt; private Point originPt; private void Ellipse_MouseDown(object sender, MouseButtonEventArgs e) { if(e.LeftButton == MouseButtonState.Pressed) { elp.CaptureMouse(); prevPt = e.GetPosition(this); } } private void Ellipse_MouseMove(object sender, MouseEventArgs e) { if(e.LeftButton == MouseButtonState.Pressed) { Vector prevVec = Point.Subtract(prevPt, originPt); Point newPt = e.GetPosition(this); Vector newVec = Point.Subtract(newPt, originPt); double deltaAngle = Vector.AngleBetween(prevVec, newVec); elpRotate.Angle += deltaAngle; UCElpAngle = elpRotate.Angle; prevPt = newPt; } } private void Ellipse_MouseUp(object sender, MouseButtonEventArgs e) { if(e.LeftButton==MouseButtonState.Released) { elp.ReleaseMouseCapture(); } } } } //window.xaml <Window x:Class="WpfApp190.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:WpfApp190" mc:Ignorable="d" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <Grid> <local:RotatedCircle UCElpAngle="{Binding DataContext.ElpAngle,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> </Grid> </Window> //window.xaml.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; 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; namespace WpfApp190 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window, INotifyPropertyChanged { public MainWindow() { InitializeComponent(); this.DataContext = this; this.Title = "0"; } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName]string propName="") { var handler=PropertyChanged; if(handler!=null) { handler?.Invoke(this, new PropertyChangedEventArgs(propName)); } } private double elpAngle; public double ElpAngle { get { return elpAngle; } set { if(value!=elpAngle) { elpAngle = value; OnPropertyChanged(nameof(ElpAngle)); Application.Current?.Dispatcher.BeginInvoke(new Action(() => { this.Title = Math.Round(ElpAngle, 2).ToString(); })); } } } } }