//uc.xaml
<UserControl x:Class="WpfApp178.UCElp"
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:WpfApp178"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="450">
<Grid>
<Ellipse
HorizontalAlignment="Left"
Width="{Binding UCElpWidth,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Height="{Binding UCElpHeight,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Stroke="Black"
StrokeThickness="10"/>
<ItemsControl x:Name="ucNumbersItemsControl"
HorizontalAlignment="Left"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding NumStr}"
FontSize="30"
Foreground="Black">
<TextBlock.RenderTransform>
<TranslateTransform
X="{Binding NumX}"
Y="{Binding NumY}"/>
</TextBlock.RenderTransform>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl x:Name="ticksItemsControl"
HorizontalAlignment="Left"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X1="{Binding LineStartX}"
Y1="{Binding LineStartY}"
X2="{Binding LineEndX}"
Y2="{Binding LineEndY}"
Stroke="{Binding LineStroke}"
StrokeThickness="{Binding LineStrokeThickness}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
//uc.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;
namespace WpfApp178
{
/// <summary>
/// Interaction logic for UCElp.xaml
/// </summary>
public partial class UCElp : UserControl
{
public UCElp()
{
InitializeComponent();
this.DataContext = this;
this.SizeChanged += UCElp_SizeChanged;
}
private void UCElp_SizeChanged(object sender, SizeChangedEventArgs e)
{
UCElpWidth = Math.Min(this.ActualWidth, this.ActualHeight);
UCElpHeight = Math.Min(this.ActualHeight, this.ActualWidth);
UCCenterX = Math.Min(this.ActualWidth, this.ActualHeight) / 2;
UCCenterY = Math.Min(this.ActualWidth, this.ActualHeight) / 2;
UCNumsList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
UCNumRadius = Math.Min(this.ActualWidth, this.ActualHeight) / 2 - 100;
UCTickRadius = Math.Min(this.ActualWidth, this.ActualHeight) / 2 - 20;
InitCircleNumbers();
InitCircleTicks();
}
private void InitCircleTicks()
{
if (UCTicksCount <= 0)
{
return;
}
double tickAngleStep = 360 / UCTicksCount;
List<UCTick> ticksList = new List<UCTick>();
for (int i = 0; i < UCTicksCount; i++)
{
double angleRadian = i * tickAngleStep * Math.PI / 180;
double startX = UCCenterX + UCTickRadius * Math.Cos(angleRadian);
double startY = UCCenterY + UCTickRadius * Math.Sin(angleRadian);
double endX = UCCenterX + (UCTickRadius - UCShortTickLength) * Math.Cos(angleRadian);
double endY = UCCenterY + (UCTickRadius - UCShortTickLength) * Math.Sin(angleRadian);
if (i % 5 == 0)
{
endX = UCCenterX + (UCTickRadius - UCLongTickLength) * Math.Cos(angleRadian);
endY = UCCenterY + (UCTickRadius - UCLongTickLength) * Math.Sin(angleRadian);
}
double tickThickness = i % 5 == 0 ? UCLongTickThickness : UCShortTickThickness;
ticksList.Add(new UCTick()
{
LineStartX = startX,
LineStartY = startY,
LineEndX = endX,
LineEndY = endY,
LineStroke = Brushes.Black,
LineStrokeThickness = tickThickness
});
}
ticksItemsControl.ItemsSource = ticksList;
}
private void InitCircleNumbers()
{
int numsCount = UCNumsList.Count;
double angelStep = 360.0d / numsCount;
List<UCNumText> numTextList = new List<UCNumText>();
for (int i = 0; i < numsCount; i++)
{
double angleRadian = ((i + 1) * angelStep - 90) * Math.PI / 180;
numTextList.Add(new UCNumText()
{
NumStr = UCNumsList[i].ToString(),
NumX = UCCenterX + (UCNumRadius) * Math.Cos(angleRadian),
NumY = UCCenterY + (UCNumRadius) * Math.Sin(angleRadian)
});
}
ucNumbersItemsControl.ItemsSource = numTextList;
}
public double UCCenterX
{
get { return (double)GetValue(UCCenterXProperty); }
set { SetValue(UCCenterXProperty, value); }
}
// Using a DependencyProperty as the backing store for UCCenterX. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCCenterXProperty =
DependencyProperty.Register("UCCenterX", typeof(double),
typeof(UCElp), new PropertyMetadata(0.0d));
public double UCCenterY
{
get { return (double)GetValue(UCCenterYProperty); }
set { SetValue(UCCenterYProperty, value); }
}
// Using a DependencyProperty as the backing store for UCCenterY. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCCenterYProperty =
DependencyProperty.Register("UCCenterY", typeof(double),
typeof(UCElp), new PropertyMetadata(0.0d));
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(UCElp), 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(UCElp), new PropertyMetadata(0.0d));
public List<int> UCNumsList
{
get { return (List<int>)GetValue(UCNumsListProperty); }
set { SetValue(UCNumsListProperty, value); }
}
// Using a DependencyProperty as the backing store for UCNumsList. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCNumsListProperty =
DependencyProperty.Register("UCNumsList", typeof(List<int>),
typeof(UCElp), new PropertyMetadata(new List<int>()));
public double UCNumRadius
{
get { return (double)GetValue(UCNumRadiusProperty); }
set { SetValue(UCNumRadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for UCNumRadius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCNumRadiusProperty =
DependencyProperty.Register("UCNumRadius", typeof(double),
typeof(UCElp), new PropertyMetadata(0.0d));
public int UCTicksCount
{
get { return (int)GetValue(UCTicksCountProperty); }
set { SetValue(UCTicksCountProperty, value); }
}
// Using a DependencyProperty as the backing store for UCTicksCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCTicksCountProperty =
DependencyProperty.Register("UCTicksCount", typeof(int),
typeof(UCElp), new PropertyMetadata(60));
public double UCShortTickLength
{
get { return (double)GetValue(UCShortTickLengthProperty); }
set { SetValue(UCShortTickLengthProperty, value); }
}
// Using a DependencyProperty as the backing store for UCShortTickLength. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCShortTickLengthProperty =
DependencyProperty.Register("UCShortTickLength", typeof(double),
typeof(UCElp), new PropertyMetadata(10.0d));
public double UCShortTickThickness
{
get { return (double)GetValue(UCShortTickThicknessProperty); }
set { SetValue(UCShortTickThicknessProperty, value); }
}
// Using a DependencyProperty as the backing store for UCShortTickThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCShortTickThicknessProperty =
DependencyProperty.Register("UCShortTickThickness", typeof(double),
typeof(UCElp), new PropertyMetadata(2.0d));
public double UCLongTickThickness
{
get { return (double)GetValue(UCLongTickThicknessProperty); }
set { SetValue(UCLongTickThicknessProperty, value); }
}
// Using a DependencyProperty as the backing store for UCLongTickThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCLongTickThicknessProperty =
DependencyProperty.Register("UCLongTickThickness", typeof(double),
typeof(UCElp), new PropertyMetadata(5.0d));
public double UCLongTickLength
{
get { return (double)GetValue(UCLongTickLengthProperty); }
set { SetValue(UCLongTickLengthProperty, value); }
}
// Using a DependencyProperty as the backing store for UCLongTickLength. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCLongTickLengthProperty =
DependencyProperty.Register("UCLongTickLength", typeof(double),
typeof(UCElp), new PropertyMetadata(20.0d));
public double UCTickRadius
{
get { return (double)GetValue(UCTickRadiusProperty); }
set { SetValue(UCTickRadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for UCTickRadius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCTickRadiusProperty =
DependencyProperty.Register("UCTickRadius", typeof(double),
typeof(UCElp), new PropertyMetadata(0.0d));
}
public class UCNumText
{
public string NumStr { get; set; }
public double NumX { get; set; }
public double NumY { get; set; }
}
public class UCTick
{
public double LineStartX { get; set; }
public double LineStartY { get; set; }
public double LineEndX { get; set; }
public double LineEndY { get; set; }
public Brush LineStroke { get; set; }
public double LineStrokeThickness { get; set; }
}
}
/main.xaml
<Window x:Class="WpfApp178.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:WpfApp178"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="450">
<Grid>
<local:UCElp/>
</Grid>
</Window>