在浏览那些充斥着昂贵商品的杂志时,注意到了一种更实惠的选择,它没有防弹玻璃。
使用Expression Blend设计了带状时钟。带子由包含TextBlock的Grid组成,这些Grid堆叠在一个Canvas类型的布局容器中。HourCanvas和其他一些元素构成了带子的视觉组件,它们被放置在另一个布局容器中,其ClipToBounds属性设置为True。
以下是当所有相关布局容器的ClipToBounds属性设置为False时的样子。
确保正确显示时间的逻辑包含在一个名为TickTock的类中。当应用程序加载时,SetTimeOnLoad方法调用了几个方法来确保正确显示时间。
Public Sub SetTimeOnLoad()
GetTime(currentHour, currentMinute_1, currentMinute_2)
' Highlight hour.
DisplayTimeOnLoad(hourCanvas, currentHour, hourStartGrid, _
hourGridUpperLimit, hourGridLowerLimit)
' Highlight first part of minutes.
DisplayTimeOnLoad(min1Canvas, currentMinute_1, min1StartGrid, _
min1GridUpperLimit, min1GridLowerLimit)
' Highlight second part of minutes.
DisplayTimeOnLoad(min2Canvas, currentMinute_2, min2StartGrid, _
min2GridUpperLimit, min2GridLowerLimit)
End Sub
GetTime方法设置了几个字段的当前时间值。
Private Sub GetTime(ByRef hour As Integer, ByRef min1 As Integer, ByRef min2 As Integer)
hour = DateTime.Now.Hour
If (hour > 12) Then
hour -= 12
End If
If (DateTime.Now.Minute.ToString.Length = 1) Then
min1 = 0
min2 = CInt(DateTime.Now.Minute.ToString.Substring(0, 1))
Else
min1 = CInt(DateTime.Now.Minute.ToString.Substring(0, 1))
min2 = CInt(DateTime.Now.Minute.ToString.Substring(1, 1))
End If
End Sub
DisplayTimeOnLoad方法确保正确显示时间。
Private Sub DisplayTimeOnLoad(ByRef cnv As Canvas, ByVal currTime As Integer, _
ByVal startGrid As Integer, ByVal upperLimit As Integer, _
ByVal lowerLimit As Integer)
If (currTime < startGrid) Then
' Move grids downwards.
shift = (startGrid - currTime) * gridHeight
While (shift > 0)
For Each grd In cnv.Children
initY = Canvas.GetTop(grd)
newY = initY + 1
Canvas.SetTop(grd, newY)
PlaceGridInLimitPosition(grd, upperLimit, lowerLimit)
Next
shift -= 1
Wend
ElseIf (currTime > startGrid) Then
' Move grids upwards.
shift = (currTime - startGrid) * gridHeight
While (shift > 0)
For Each grd In cnv.Children
initY = Canvas.GetTop(grd)
newY = initY - 1
Canvas.SetTop(grd, newY)
PlaceGridInLimitPosition(grd, upperLimit, lowerLimit)
Next
shift -= 1
Wend
End If
End Sub
在上面的方法中,相关的Grid要么向上移动,要么向下移动,以便正确显示时间。PlaceGridInLimitPosition确保移动超出某个限制的Grid被相应地放置。
Private Sub PlaceGridInLimitPosition(ByRef grd As Grid, ByVal upperLimit As Integer, _
ByVal lowerLimit As Integer)
If (upperLimit = hourGridUpperLimit) AndAlso (lowerLimit = hourGridLowerLimit) Then
If (newY >= 280) Then
Canvas.SetTop(grd, hourGridUpperLimit)
ElseIf (newY <= -240) Then
Canvas.SetTop(grd, hourGridLowerLimit)
End If
ElseIf (upperLimit = min1GridUpperLimit) AndAlso (lowerLimit = min1GridLowerLimit) Then
If (newY >= 120) Then
Canvas.SetTop(grd, min1GridUpperLimit)
ElseIf (newY <= -160) Then
Canvas.SetTop(grd, min1GridLowerLimit)
End If
ElseIf (upperLimit = min2GridUpperLimit) AndAlso (lowerLimit = min2GridLowerLimit) Then
If (newY >= 200) Then
Canvas.SetTop(grd, min2GridUpperLimit)
ElseIf (newY <= -240) Then
Canvas.SetTop(grd, min2GridLowerLimit)
End If
End If
End Sub
TimeKeeper_Tick方法处理DispatcherTimer对象的Tick事件,其Interval属性设置为1秒,并确保时间变化时正确显示时间。
Private Sub TimeKeeper_Tick(ByVal sender As Object, ByVal e As EventArgs)
GetTime(currHour, currMin1, currMin2)
' Set new hour.
If (currentHour <> currHour) Then
DisplayNewTime(hourCanvas, hourGridLowerLimit, hourGridUpperLimit)
currentHour = currHour
End If
' Set new first part of minutes.
If (currentMinute_1 <> currMin1) Then
DisplayNewTime(min1Canvas, min1GridLowerLimit, min1GridUpperLimit)
currentMinute_1 = currMin1
End If
' Set new second part of minutes.
If (currentMinute_2 <> currMin2) Then
DisplayNewTime(min2Canvas, min2GridLowerLimit, min2GridUpperLimit)
currentMinute_2 = currMin2
End If
End Sub
DisplayNewTime方法导致执行动画,创建滚动效果。
Private Sub DisplayNewTime(ByRef cnv As Canvas, ByVal lowerLimit As Integer, _
ByVal upperLimit As Integer)
For Each grd As Grid In cnv.Children
initY = Canvas.GetTop(grd)
If (initY <= upperLimit) Then
dblGridAnim.Duration = TimeSpan.FromMilliseconds(1)
dblGridAnim.To = lowerLimit
dblGridAnim.FillBehavior = FillBehavior.HoldEnd
grd.BeginAnimation(Canvas.TopProperty, dblGridAnim)
Else
newY = initY - gridHeight
dblGridAnim.Duration = TimeSpan.FromMilliseconds(800)
dblGridAnim.To = newY
dblGridAnim.FillBehavior = FillBehavior.HoldEnd
grd.BeginAnimation(Canvas.TopProperty, dblGridAnim)
End If
Next
End Sub