WPF line rotate around the start center at ease

//xaml
<Window x:Class="WpfApp220.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"
        WindowState="Maximized"
        xmlns:local="clr-namespace:WpfApp220"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Ellipse x:Name="elp"
                 Stroke="Black"
                 StrokeThickness="10"
                 Width="{Binding ElpWidth,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 Height="{Binding ElpHeight,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 RenderTransformOrigin="0.5,0.5" >
            <Ellipse.Fill>
                <!--<LinearGradientBrush StartPoint="0,0" EndPoint="0,0.2" SpreadMethod="Reflect">
                    <GradientStop Offset="0.0" Color="Red"/>
                    <GradientStop Offset="0.1" Color="Black"/>
                    <GradientStop Offset="0.2" Color="Red"/>
                    <GradientStop Offset="0.3" Color="Black"/>
                    <GradientStop Offset="0.4" Color="Red"/>
                    <GradientStop Offset="0.5" Color="Black"/>
                    <GradientStop Offset="0.6" Color="Red"/>
                    <GradientStop Offset="0.7" Color="Black"/>
                    <GradientStop Offset="0.8" Color="Red"/>
                    <GradientStop Offset="0.9" Color="Black"/>
                    <GradientStop Offset="1" Color="Red"/>
                </LinearGradientBrush>-->
                <ImageBrush ImageSource="{Binding ImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
            </Ellipse.Fill>
            <Ellipse.RenderTransform>
                <RotateTransform x:Name="elpRotater"/>
            </Ellipse.RenderTransform>
        </Ellipse>

        <ItemsControl x:Name="ticksItemsControl"                       
                      >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Line X1="{Binding TickStartX}"
                          Y1="{Binding TickStartY}"
                          X2="{Binding TickEndX}"
                          Y2="{Binding TickEndY}"
                          Stroke="{Binding TickStroke}"
                          StrokeThickness="{Binding TickThickness}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.RenderTransform>
                <RotateTransform CenterX="{Binding CenterX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                 CenterY="{Binding CenterY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
            </ItemsControl.RenderTransform>
        </ItemsControl>

        <Ellipse Width="100"
                 Height="100"
                 Stroke="Black"
                 StrokeThickness="10"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"/>

        <Line Stroke="Red"
              StrokeThickness="10"
              StrokeStartLineCap="Round"
              StrokeEndLineCap="Triangle"
              X1="{Binding CenterX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
              Y1="{Binding CenterY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
              X2="{Binding LineEndX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
              Y2="{Binding LineEndY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
              RenderTransformOrigin="0.5,0.5">
            <Line.RenderTransform>
                <RotateTransform x:Name="lineRotater"/>
            </Line.RenderTransform>
        </Line>
        
        
    </Grid>
</Window>






//cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WpfApp220
{
    /// <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;
        private RotateTransform elpRotater;
        private DoubleAnimation animation;
        private RotateTransform lineRotater;
        public MainVM(Window winValue)
        {
            win = winValue;
            if (win != null)
            {
                win.Loaded += Win_Loaded;
                win.SizeChanged += Win_SizeChanged;
            }
        }

        private void Win_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Init();
        }

        private void Win_Loaded(object sender, RoutedEventArgs e)
        {
            Init();
        }

        private System.Timers.Timer tmr;
        private void Init()
        {
            var fe = win.Content as FrameworkElement;
            if (fe != null)
            {
                ElpWidth = fe.ActualHeight;
                ElpHeight = fe.ActualHeight;
                TickRadius = fe.ActualHeight / 2 - 50;
                CenterX = fe.ActualWidth / 2;
                CenterY = fe.ActualHeight / 2;
                LineEndX = fe.ActualWidth / 2;
                LineEndY = 15;
            }
            if (tmr == null)
            {
                tmr = new System.Timers.Timer();
                tmr.Elapsed += Tmr_Elapsed;
                tmr.Interval = 1000;
                tmr.Start();
            }

            //var tempRotater = win.FindName("elpRotater") as RotateTransform;
            //if (tempRotater != null)
            //{
            //    elpRotater = tempRotater;
            //    animation = new DoubleAnimation();
            //    animation.From = 0;
            //    animation.To = 360;
            //    animation.RepeatBehavior = RepeatBehavior.Forever;
            //    animation.Duration = TimeSpan.FromSeconds(12);
            //    elpRotater.BeginAnimation(RotateTransform.AngleProperty, animation);
            //}

            InitTicks();

            var tempLineRotater = win.FindName("lineRotater") as RotateTransform;
            if(tempLineRotater != null)
            {
                lineRotater = tempLineRotater;
                animation = new DoubleAnimation();
                animation.From = 0;
                animation.To = 360;
                animation.RepeatBehavior = RepeatBehavior.Forever;
                animation.Duration = TimeSpan.FromSeconds(12);
                lineRotater.BeginAnimation(RotateTransform.AngleProperty, animation);
            }
        }

        private void InitTicks()
        {
            int ticksCount = 60;
            Brush tempTickStroke = Brushes.Black;
            double tempTickThickess = 2;
            double tickLength = 30;            
            double angleStep = 360 / 60;
            double angleRadian = 0;
            TicksList = new List<TickClass>();
            for (int i = 0; i < ticksCount; i++)
            {
                angleRadian = (i * angleStep - 90) * Math.PI / 180;
                tickLength = i % 5 == 0 ? 50 : 30;
                tempTickStroke = i % 5 == 0 ? Brushes.Red : Brushes.Black;
                tempTickThickess = i % 5 == 0 ? 5 : 2;
                TicksList.Add(new TickClass()
                {
                    TickStartX = CenterX + TickRadius * Math.Cos(angleRadian),
                    TickStartY = CenterY + TickRadius * Math.Sin(angleRadian),
                    TickEndX = CenterX + (TickRadius + tickLength) * Math.Cos(angleRadian),
                    TickEndY = CenterY + (TickRadius + tickLength) * Math.Sin(angleRadian),
                    TickStroke = tempTickStroke,
                    TickThickness = tempTickThickess
                });
            }

            var itemsControl = win.FindName("ticksItemsControl") as ItemsControl;
            if(itemsControl != null)
            {
                itemsControl.ItemsSource = TicksList;
            }
        }

        private void Tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {

        }

        private double lineEndX;
        public double LineEndX
        {
            get
            {
                return lineEndX;
            }
            set
            {
                if (value != lineEndX)
                {
                    lineEndX = value;
                    OnPropertyChanged(nameof(LineEndX));
                }
            }
        }

        private double lineEndY;
        public double LineEndY
        {
            get
            {
                return lineEndY;
            }
            set
            {
                if (value != lineEndY)
                {
                    lineEndY = value;
                    OnPropertyChanged(nameof(LineEndY));
                }
            }
        }

        private List<TickClass> ticksList;
        public List<TickClass> TicksList
        {
            get
            {
                return ticksList;
            }
            set
            {
                if (ticksList != value)
                {
                    ticksList = value;
                    OnPropertyChanged(nameof(TicksList));
                }
            }
        }

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

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

        private double tickRadius;
        public double TickRadius
        {
            get
            {
                return tickRadius;
            }
            set
            {
                if (value != tickRadius)
                {
                    tickRadius = value;
                    OnPropertyChanged(nameof(TickRadius));
                }
            }
        }

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

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

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

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


    public class TickClass
    {
        public double TickStartX { get; set; }
        public double TickStartY { get; set; }
        public double TickEndX { get; set; }
        public double TickEndY { get; set; }
        public Brush TickStroke { get; set; }
        public double TickThickness { get; set; }
    }
}

 

 

 

 

 

 

 

 

 

posted @ 2025-04-27 14:47  FredGrit  阅读(11)  评论(0)    收藏  举报