C#WPF时钟-自定义控件

C#WPF时钟-自定义控件


参考:
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;
    }
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值