<Window x:Class="WpfApp185.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:WpfApp185"
mc:Ignorable="d"
WindowState="Maximized"
KeyDown="Window_KeyDown"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Path x:Name="circlePath"
Stroke="Black"
StrokeThickness="5"
Panel.ZIndex="-1">
<Path.Data>
<EllipseGeometry
Center="{Binding ElpCenter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
RadiusX="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
RadiusY="{Binding ElpRadius,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</Path.Data>
</Path>
<ItemsControl x:Name="ticksItemsControl"
Panel.ZIndex="1">
<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 TickStrokeThickness}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Ellipse Width="50"
Height="50"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Stroke="Red"
StrokeThickness="5"
Panel.ZIndex="2"/>
<Line Panel.ZIndex="3"
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}"
Stroke="Red"
StrokeThickness="5">
<Line.RenderTransform>
<RotateTransform x:Name="rotater"
CenterX="{Binding CenterX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
CenterY="{Binding CenterY,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</Line.RenderTransform>
</Line>
</Grid>
</Window>
//cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
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 WpfApp185
{
/// <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 void Init()
{
var fe = this.Content as FrameworkElement;
if (fe != null)
{
CenterX = fe.ActualWidth / 2;
CenterY = fe.ActualHeight / 2;
ElpCenter = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
ElpRadius = fe.ActualHeight / 2 - 50;
LineEndX = fe.ActualWidth / 2;
LineEndY = 60;
InitTicks();
InitLineTickTimer();
}
}
private System.Timers.Timer lineTmr { get; set; }
Random lineRnd { get; set; }
private void InitLineTickTimer()
{
if (lineTmr != null)
{
return;
}
lineTmr = new System.Timers.Timer();
lineTmr.Elapsed += LineTmr_Elapsed;
lineTmr.Interval = 1000;
lineTmr.Start();
}
private void LineTmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (isPaused)
{
return;
}
try
{
lineRnd = new Random();
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
{
double lineAngle = lineRnd.Next(0, 360);
rotater.Angle = lineAngle;
this.Title = rotater.Angle.ToString();
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace.ToString());
}
}
private void InitTicks()
{
List<TickClass> ticksList = new List<TickClass>();
double angleStep = 360 / 360;
double tickLength = 0;
double tickTickness = 0;
Brush tickStroke = Brushes.Black;
for (int i = 0; i < 360; i++)
{
tickLength = i % 5 == 0 ? 30 : 15;
tickTickness = i % 5 == 0 ? 2 : 1;
tickStroke = i % 5 == 0 ? Brushes.Red : Brushes.Black;
double angleRadian = (i * angleStep - 90) * Math.PI / 180;
ticksList.Add(new TickClass()
{
TickStartX = CenterX + ElpRadius * Math.Cos(angleRadian),
TickStartY = CenterY + ElpRadius * Math.Sin(angleRadian),
TickEndX = CenterX + (ElpRadius - tickLength) * Math.Cos(angleRadian),
TickEndY = CenterY + (ElpRadius - tickLength) * Math.Sin(angleRadian),
TickStroke = tickStroke,
TickThickness = tickTickness
});
}
ticksItemsControl.ItemsSource = ticksList;
}
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 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 elpRadius;
public double ElpRadius
{
get
{
return elpRadius;
}
set
{
if (value != elpRadius)
{
elpRadius = value;
OnPropertyChanged(nameof(ElpRadius));
}
}
}
private Point elpCenter;
public Point ElpCenter
{
get
{
return elpCenter;
}
set
{
if (value != elpCenter)
{
elpCenter = value;
OnPropertyChanged(nameof(ElpCenter));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
bool isPaused = false;
private void Window_KeyDown(object sender, KeyEventArgs e)
{
isPaused = !isPaused;
}
}
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; }
}
}
![]()
![]()
![]()