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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-04-04 11:17  FredGrit  阅读(10)  评论(0)    收藏  举报