WPF学习————制作时钟
话不多说,这个实例非常适合入门者。主要的东西是路径Path。然后是RenderTransfer和数据绑定。不熟悉的请先阅读相关知识,也可以根据实例来一边实践一边学习。
先上效果:
整体结构如下:
窗体设置:
Height="450" Width="450" ResizeMode="NoResize" WindowStyle="None"
xaml层次:
<Border Background="LightCyan"> <Grid> <Ellipse Stroke="Black" StrokeThickness="10" Margin="10"></Ellipse> <Ellipse Stroke="Gray" StrokeThickness="1" Width="350" Height="350"></Ellipse> <Ellipse Stroke="Gray" StrokeThickness="1" Width="380" Height="380"></Ellipse> <Ellipse StrokeThickness="5" Fill="White" Width="20" Height="20" Stroke="Black" ></Ellipse> <TextBlock Text="12" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="205" Y="50"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="1" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="290" Y="80"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="2" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="340" Y="130"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="3" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="370" Y="200"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="4" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="350" Y="280"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="5" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="300" Y="340"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="6" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="215" Y="360"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="8" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="80" Y="280"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="7" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="140" Y="340"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="9" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="60" Y="205"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="11" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="140" Y="80"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="10" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="85" Y="130"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="0" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="90" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="180" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="270" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="30" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="60" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="120" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="150" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="210" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="240" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="300" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="330" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Yellow" StrokeThickness="1" Name="seconds"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.second_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF2BE60E" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,60 220,200 225,225 225,250 225,225 230,200 z"> </PathGeometry> </Path.Data> <!--<Path.Triggers> <EventTrigger RoutedEvent="Loaded"> --><!--<BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="seconds" Storyboard.TargetProperty="RenderTransform.Angle" Duration="00:01:00" From="0" To="360" By="6" RepeatBehavior="Forever"></DoubleAnimation> </Storyboard> </BeginStoryboard>--><!-- </EventTrigger> </Path.Triggers>--> </Path> <Path Stroke="Black" StrokeThickness="2"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.minius_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF157AF3" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,80 215,200 225,225 225,250 225,225 235,200 z"> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="2"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.hours_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFE233AA" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,120 200,200 225,225 225,250 225,225 250,200 z"> </PathGeometry> </Path.Data> </Path> </Grid> </Border>
1:先设计静态的东西。时钟的面板上的,最外面的大黑圆。数值对应的分度圆。
<Ellipse Stroke="Black" StrokeThickness="10" Margin="10"></Ellipse> <Ellipse Stroke="Gray" StrokeThickness="1" Width="350" Height="350"></Ellipse> <Ellipse Stroke="Gray" StrokeThickness="1" Width="380" Height="380"></Ellipse> <Ellipse StrokeThickness="5" Fill="White" Width="20" Height="20" Stroke="Black" ></Ellipse>
2:设计数字,并安排到合适的位置,注意数值对应的黑点也是Path。
<TextBlock Text="12" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="205" Y="50"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="1" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="290" Y="80"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="2" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="340" Y="130"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="3" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="370" Y="200"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="4" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="350" Y="280"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="5" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="300" Y="340"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="6" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="215" Y="360"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="8" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="80" Y="280"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="7" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="140" Y="340"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="9" FontSize="35" > <TextBlock.RenderTransform> <TranslateTransform X="60" Y="205"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="11" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="140" Y="80"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="10" FontSize="25" > <TextBlock.RenderTransform> <TranslateTransform X="85" Y="130"></TranslateTransform> </TextBlock.RenderTransform> </TextBlock> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="0" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="90" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="180" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="3"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="270" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="30" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="60" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="120" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="150" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="210" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="240" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="300" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry Figures="M 225,35 225,50"> <PathGeometry.Transform> <RotateTransform Angle="330" CenterX="225" CenterY="225"></RotateTransform> </PathGeometry.Transform> </PathGeometry> </Path.Data> </Path>
3:用Path设计好时针,分针,秒针的形状,并加入渐变效果。
<Path Stroke="Yellow" StrokeThickness="1" Name="seconds"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.second_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF2BE60E" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,60 220,200 225,225 225,250 225,225 230,200 z"> </PathGeometry> </Path.Data> <!--<Path.Triggers> <EventTrigger RoutedEvent="Loaded"> --><!--<BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="seconds" Storyboard.TargetProperty="RenderTransform.Angle" Duration="00:01:00" From="0" To="360" By="6" RepeatBehavior="Forever"></DoubleAnimation> </Storyboard> </BeginStoryboard>--><!-- </EventTrigger> </Path.Triggers>--> </Path> <Path Stroke="Black" StrokeThickness="2"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.minius_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF157AF3" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,80 215,200 225,225 225,250 225,225 235,200 z"> </PathGeometry> </Path.Data> </Path> <Path Stroke="Black" StrokeThickness="2"> <Path.RenderTransform> <RotateTransform CenterX="225" CenterY="225" Angle="{Binding clockTimeData.hours_indicate, UpdateSourceTrigger=PropertyChanged}"> </RotateTransform> </Path.RenderTransform> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFE233AA" Offset="0.3"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <PathGeometry Figures="M 225,120 200,200 225,225 225,250 225,225 250,200 z"> </PathGeometry> </Path.Data> </Path>
4:建立时分秒对应的数据,并开notifypropertychange。
public class ClockTimeData:NotifyPropertyChange { public ClockTimeData() { } double _second_indicate; public double second_indicate { set { _second_indicate = value; RaisePropertyChanged(nameof(second_indicate)); } get { return _second_indicate; } } double _minius_indicate; public double minius_indicate { set { _minius_indicate = value; RaisePropertyChanged(nameof(minius_indicate)); } get { return _minius_indicate; } } public double hours_indicate { set; get; } }
5:建立ViewModel.搭建数据和UI的关联逻辑。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using WPFClock.Modles; using MVVMLibrary.MVVMCommon; using MVVMLibrary.MVVMBase; namespace WPFClock.ViewModles { public class ClolcTimeVM:ViewModelBase { public ClockTimeData clockTimeData { set; get; } Action Updateindicate; public ClolcTimeVM() { clockTimeData = new ClockTimeData(); Updateindicate += Updateindicatefun; Updateindicate.BeginInvoke( ar=>Updateindicate.EndInvoke(ar) ,null); } private void Updateindicatefun() { while(true) { clockTimeData.second_indicate = DateTime.Now.Second*6.0; clockTimeData.minius_indicate = DateTime.Now.Minute * 6.0+ DateTime.Now.Second/60.0*6; double hour = DateTime.Now.Hour > 12 ? (DateTime.Now.Hour - 12) : DateTime.Now.Hour; clockTimeData.hours_indicate = hour * 30.0+ DateTime.Now.Minute / 60.0*30; Thread.Sleep(200); } } } }
6:将UI的datacontex设置到ViewModel.
<Window.DataContext> <vm:ClolcTimeVM></vm:ClolcTimeVM> </Window.DataContext>
7:运行后,时针,分针,秒针将根据当前的计算机时间来布置和运动。
clockTimeData.second_indicate = DateTime.Now.Second*6.0; clockTimeData.minius_indicate = DateTime.Now.Minute * 6.0+ DateTime.Now.Second/60.0*6; double hour = DateTime.Now.Hour > 12 ? (DateTime.Now.Hour - 12) : DateTime.Now.Hour; clockTimeData.hours_indicate = hour * 30.0+ DateTime.Now.Minute / 60.0*30;