WPF Ellipse rotate around the center via customized usercontrol

//usercontrol
//xaml
<UserControl x:Class="WpfApp48.UCRotatedElp"
             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:WpfApp48"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Ellipse 
                Width="{Binding ElpWidthDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                Height="{Binding ElpHeightDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                >
            <Ellipse.Fill>
                <ImageBrush ImageSource="{Binding ImgSourceDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
            </Ellipse.Fill>
            <Ellipse.RenderTransform>
                <TransformGroup>
                    <RotateTransform CenterX="{Binding CenterXDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     CenterY="{Binding CenterYDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     Angle="{Binding AngleDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     />
                </TransformGroup>
            </Ellipse.RenderTransform>
        </Ellipse>
    </Grid>
</UserControl>


//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;

namespace WpfApp48
{
    /// <summary>
    /// Interaction logic for UCRotatedElp.xaml
    /// </summary>
    public partial class UCRotatedElp : UserControl
    {
        public UCRotatedElp()
        {
            InitializeComponent();
            this.DataContext=this;
        }



        public double ElpWidthDP
        {
            get { return (double)GetValue(ElpWidthDPProperty); }
            set { SetValue(ElpWidthDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElpWidthDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElpWidthDPProperty =
            DependencyProperty.Register("ElpWidthDP", typeof(double), 
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));






        public double ElpHeightDP
        {
            get { return (double)GetValue(ElpHeightDPProperty); }
            set { SetValue(ElpHeightDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElpHeightDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElpHeightDPProperty =
            DependencyProperty.Register("ElpHeightDP", typeof(double), 
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));






        public Brush ElpFillBrushDP
        {
            get { return (Brush)GetValue(ElpFillBrushDPProperty); }
            set { SetValue(ElpFillBrushDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElpFillBrushDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElpFillBrushDPProperty =
            DependencyProperty.Register("ElpFillBrushDP", typeof(Brush), 
                typeof(UCRotatedElp), new PropertyMetadata(new SolidColorBrush(Colors.Black)));





        public double CenterXDP
        {
            get { return (double)GetValue(CenterXDPProperty); }
            set { SetValue(CenterXDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CenterXDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CenterXDPProperty =
            DependencyProperty.Register("CenterXDP", typeof(double), 
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));






        public double CenterYDP
        {
            get { return (double)GetValue(CenterYDPProperty); }
            set { SetValue(CenterYDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CenterYDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CenterYDPProperty =
            DependencyProperty.Register("CenterYDP", typeof(double), 
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));





        public ImageSource ImgSourceDP
        {
            get { return (ImageSource)GetValue(ImgSourceDPProperty); }
            set { SetValue(ImgSourceDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImgSourceDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImgSourceDPProperty =
            DependencyProperty.Register("ImgSourceDP", typeof(ImageSource), 
                typeof(UCRotatedElp), new PropertyMetadata(null));




        public double AngleDP
        {
            get { return (double)GetValue(AngleDPProperty); }
            set { SetValue(AngleDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AngleDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AngleDPProperty =
            DependencyProperty.Register("AngleDP", typeof(double), 
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));



    }
}

 

 

//window
//xaml
<Window x:Class="WpfApp48.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:WpfApp48"
        WindowState="Maximized"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:UCRotatedElp
            ElpWidthDP="{Binding DataContext.ElpWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            ElpHeightDP="{Binding DataContext.ElpHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            CenterXDP="{Binding DataContext.CenterX,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            CenterYDP="{Binding DataContext.CenterY,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            ImgSourceDP="{Binding DataContext.ImgSource,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
            AngleDP="{Binding DataContext.ElpAngle,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>


//cs
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
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.Windows.Threading;

namespace WpfApp48
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainVM(this);
            this.DataContext=vm;
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private Window win;
        public MainVM(Window winValue)
        {
            win=winValue;
            if (win!=null)
            {
                win.Loaded+=Win_Loaded;
            }
        }

        private void Win_Loaded(object sender, RoutedEventArgs e)
        {
            ElpWidth=win.ActualHeight/2;
            ElpHeight=win.ActualHeight/2;
            CenterX=ElpWidth/2;
            CenterY=ElpHeight/2;
            ImgSource=GetImageSourceViaUrl(@"../../../Images/1.jpg");
            ElpAngle=0;
            DispatcherTimer tmr = new DispatcherTimer();
            tmr.Interval=TimeSpan.FromSeconds(1);
            tmr.Tick+=Tmr_Tick;
            tmr.Start();
        }

        private void Tmr_Tick(object? sender, EventArgs e)
        {
            ElpAngle = (ElpAngle + 2) % 360;
        }

        private ImageSource GetImageSourceViaUrl(string imgUrl)
        {
            if (!File.Exists(imgUrl))
            {
                return null;
            }
            BitmapImage bmi = new BitmapImage();
            bmi.BeginInit();
            bmi.UriSource=new Uri(imgUrl, UriKind.RelativeOrAbsolute);
            bmi.EndInit();
            if (bmi.CanFreeze)
            {
                bmi.Freeze();
            }
            return bmi;
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propName = "")
        {
            var handler = PropertyChanged;
            if (handler!=null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }

        private double elpWidth;
        public double ElpWidth
        {
            get
            {
                return elpWidth;
            }
            set
            {
                if (value!=elpWidth)
                {
                    elpWidth=value;
                    OnPropertyChanged();
                }
            }
        }

        private double elpHeight;
        public double ElpHeight
        {
            get
            {
                return elpHeight;
            }
            set
            {
                if (value!=elpHeight)
                {
                    elpHeight=value;
                    OnPropertyChanged();
                }
            }
        }


        private double centerX;
        public double CenterX
        {
            get
            {
                return centerX;
            }
            set
            {
                if (value!=centerX)
                {
                    centerX=value;
                    OnPropertyChanged();
                }
            }
        }

        private double centerY;
        public double CenterY
        {
            get
            {
                return centerY;
            }
            set
            {
                if (value!=centerY)
                {
                    centerY=value;
                    OnPropertyChanged();
                }
            }
        }

        private ImageSource imgSource;
        public ImageSource ImgSource
        {
            get
            {
                return imgSource;
            }
            set
            {
                if (value!=imgSource)
                {
                    imgSource=value;
                    OnPropertyChanged();
                }
            }
        }

        private double elpAngle;
        public double ElpAngle
        {
            get
            {
                return elpAngle;
            }
            set
            {
                if (value!=elpAngle)
                {
                    elpAngle=value;
                    OnPropertyChanged();
                }
            }
        }
    }
}

 

 

 

 

image

 

 

 

image

 

posted @ 2025-08-20 11:41  FredGrit  阅读(9)  评论(0)    收藏  举报