WPF a triangle rotate around the bigger circle and always point to the center

//xaml
<Window x:Class="WpfApp182.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:WpfApp182"
        mc:Ignorable="d"
        KeyDown="Window_KeyDown"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Path x:Name="triPath" Fill="Red">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="0,0" IsClosed="True">
                        <LineSegment Point="20,0"/>
                        <LineSegment Point="10,50"/>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
            <Path.RenderTransform>
                <TransformGroup>
                    <TranslateTransform x:Name="translater"
                                        X="{Binding TX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                        Y="{Binding TY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                    <RotateTransform x:Name="rotater"
                                     CenterX="{Binding TCenterX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     CenterY="{Binding TCenterY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>


        <Ellipse Width="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 Height="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 Stroke="Blue"
                 StrokeThickness="5"
                 VerticalAlignment="Center"
                 HorizontalAlignment="Center"
                 Panel.ZIndex="-1"/>
    </Grid>
</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 WpfApp182
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.Loaded += MainWindow_Loaded;
            this.SizeChanged += MainWindow_SizeChanged;
        }

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

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

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

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

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

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

        private Point elpCenter;
        public Point ElpCenter
        {
            get
            {
                return elpCenter;
            }
            set
            {
                if (value != elpCenter)
                {
                    elpCenter = value;
                    OnPropertyChanged(nameof(ElpCenter));
                }
            }
        }

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

        private bool isPaused = false;

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

        private System.Timers.Timer tmr { get; set; }

        private void Init()
        {
            var fe = this.Content as FrameworkElement;
            if (fe != null)
            {
                TCenterX= fe.ActualWidth / 2;
                TCenterY = fe.ActualHeight / 2;
                TX = fe.ActualWidth / 2 - 15;
                TY = 0;
                ElpCenter = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
                ElpRadius = fe.ActualHeight - 50;                 
            }

            if (tmr != null)
            {
                return;
            }

            tmr = new System.Timers.Timer();
            tmr.Interval = 1000;
            tmr.Elapsed += Tmr_Elapsed;
            tmr.Start();
        }

        private void Tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if(isPaused)
            {
                return;
            }
            try
            {
                Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
                {
                    rotater.Angle += 10;
                    if (rotater.Angle >= 360)
                    {
                        rotater.Angle = 0;
                    }
                    this.Title = rotater.Angle.ToString();
                    Console.WriteLine(Mouse.GetPosition(triPath).X + "," + Mouse.GetPosition(triPath).Y);
                }));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message+"\n"+ex.StackTrace.ToString());
            }
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            isPaused = !isPaused;
        }

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-03-29 14:21  FredGrit  阅读(10)  评论(0)    收藏  举报