参考:
https://www.cnblogs.com/banluqiaodaima/p/15249768.html
https://www.cnblogs.com/Cyril-hcj/p/15171791.html
效果
实现
1.新建用户控件”Clock.xaml“
2.首先在xml中绘制时钟外框和中心点👇
<Ellipse HorizontalAlignment="Center" Height="6" Stroke="Black" StrokeThickness="3" VerticalAlignment="Center" Width="6" />
<Ellipse Width="200" Height="200" Stroke="Black" StrokeThickness="2" Name="BackEllipse" />
3.画刻度👇
<Canvas x:Name="MainCanvas"
Width="{Binding Width,ElementName=BackEllipse}"
Height="{Binding Height,ElementName=BackEllipse}"/>
/// <summary>
/// 绘制时钟刻度
/// </summary>
private void DoDraw()
{
double radius = 100;//时钟半径
double min = 0; double max = 60;
double step = 360.0 / (max - min);
Line lineScale = null;
Label label = null;
for (int i = 0; i < max - min; i++)
{
//刻度线是从3点钟开始画的
if (i % 5 == 0)
{
//长刻度线,长度为8
lineScale = new Line
{
X1 = ((radius - 8) * Math.Cos(i * step * Math.PI / 180)) + radius,
Y1 = ((radius - 8) * Math.Sin(i * step * Math.PI / 180)) + radius,
X2 = (radius * Math.Cos(i * step * Math.PI / 180)) + radius,
Y2 = (radius * Math.Sin(i * step * Math.PI / 180)) + radius,
Stroke = Brushes.Black,
StrokeThickness = 1
};
label = new Label
{
Content = i / 5 + 3 > 12 ? i / 5 + 3 - 12 : i / 5 + 3,
//因为当写到“12”时,只有“12”的位置会有偏差,所以直接定义“12”的位置
Margin = i / 5 + 3 == 12 ? new Thickness(100 - 7, 8, 0, 0) : new Thickness(((radius - 12) * Math.Cos(i * step * Math.PI / 180)) + radius - 3, ((radius - 12) * Math.Sin(i * step * Math.PI / 180)) + radius - 7, 0, 0),
Padding = new Thickness(0, 0, 0, 0),
Foreground = Brushes.Black
};
MainCanvas.Children.Add(label);
}
else
{
//短刻度线,长度为5
lineScale = new Line
{
X1 = ((radius - 5) * Math.Cos(i * step * Math.PI / 180)) + radius,
Y1 = ((radius - 5) * Math.Sin(i * step * Math.PI / 180)) + radius,
X2 = (radius * Math.Cos(i * step * Math.PI / 180)) + radius,
Y2 = (radius * Math.Sin(i * step * Math.PI / 180)) + radius,
Stroke = Brushes.Black,
StrokeThickness = 1
};
}
MainCanvas.Children.Add(lineScale);
}
}
4.画表针,RotateTransform中的CenterX和CenterY表示绕此点旋转,Angle为旋转角度👇
<Line x:Name="lineHour" X1="100" Y1="100" X2="100" Y2="32" Stroke="Black" StrokeThickness="2">
<Line.RenderTransform>
<RotateTransform x:Name="lineHourRotate" CenterX="100" CenterY="100" Angle="0" />
</Line.RenderTransform>
</Line>
<Line x:Name="lineMinute" X1="100" Y1="100" X2="100" Y2="16" Stroke="Black" StrokeThickness="2">
<Line.RenderTransform>
<RotateTransform x:Name="lineMinuteRotate" CenterX="100" CenterY="100" Angle="0" />
</Line.RenderTransform>
</Line>
<Line x:Name="lineSecond" X1="100" Y1="110" X2="100" Y2="16" Stroke="Black" StrokeThickness="1">
<Line.RenderTransform>
<RotateTransform x:Name="lineSecondRotate" CenterX="100" CenterY="100" Angle="0" />
</Line.RenderTransform>
</Line>
然后在”Clock.xaml.cs“中写定时器
//DispatcherTimer和Timer区别:DispatcherTimer是直接运行在UI线程中的,可以直接操作UI;如果使用Timer,需要使用Task.Run操作UI
private System.Windows.Threading.DispatcherTimer timer = null;
DateTime now;
public Clock()
{
InitializeComponent();
DoDraw();//时钟刻度初始化
//表针位置初始化,若没有此步骤,在进入界面时,可观察到表针会突然从初始位置(12点钟)变换到当前时间位置
HandChange();
//timer初始化
if (timer == null)
{
timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1000);//1秒/次
timer.Tick += Timer_Tick;
timer.Start();
}
}
private void Timer_Tick(object sender, EventArgs e)
{
//throw new NotImplementedException();
HandChange();
}
/// <summary>
/// 根据当前时间变换表针位置,并更新label时间
/// </summary>
private void HandChange()
{
now = DateTime.Now;//当前时间
double hour = now.Hour > 12 ? (now.Hour - 12) : now.Hour;//当前小时(24小时转为12小时,因为时钟是12小时的)
lineSecondRotate.Angle = now.Second * 6.0;//秒针
lineMinuteRotate.Angle = now.Minute * 6.0 + now.Second / 60.0 * 6.0;//分针
lineHourRotate.Angle = hour * 30.0 + now.Minute * 60.0 * 30.0;//时针
labelDate.Content = now.ToShortDateString() + " " + now.ToString("dddd");//YYYY/MM/DD 星期X
labelTime.Content = now.ToLongTimeString();//HH:mm:ss
}
5.最后在Unload事件中关闭定时器并置空
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
if (timer.IsEnabled)
{
timer.Stop();
timer = null;
}
}