WPF 2D 图像轮播






4.95/5 (31投票s)
WPF 中的 2D 轮播用户控件

引言
这篇文章描述了我如何创建 2D 图片轮播图。创建它的原因...我只是想看看我是否能做到。我实际上是在看一个黑莓 Playbook 的 视频,我想知道我是否可以创建一个类似于视频中轮播图功能的控件。Playbook 的虽然更优雅,我可能会羡慕不已。我的轮播图 UserControl
,恰如其分地命名为 ImageCarousel
,只处理图片,而且只有五张图片。虽然这可能很可悲,但你希望从这篇文章中获得一些有用的东西,所以如果你仍然感兴趣,请继续阅读。
要求
要运行从上面的下载链接提供的项目,你需要以下之一
- Visual Studio 2010
- Expression Blend
注意:如果你正在使用 Visual Studio 的 Express 版本,请确保使用 Visual Basic Express 打开解决方案。
ImageCarousel
工作原理
要移动图片,请按住鼠标左键并向左或向右拖动。当你松开鼠标左键时,图片将按预定方向移动。
设计和布局
我在 Expression Blend 中把所有东西放在一起。下图显示了一些元素在 UserControl
中的布局
在上面的图像中,有五个主要的 Grid
控件可见,另外还有五个 Grid
控件位于主 ImageGrid
的左侧和右侧。下图显示了位于主 Grid
左侧的 Grid
。
位于主 Grid
左侧和右侧的 Grid
控件实际上是主 Grid
的副本。我稍后会解释为什么我们需要它们。
注意:CarouselCanvas
的 ClipToBounds
属性设置为 True。
代码
在 ImageCarousel
的 Initialized
事件处理程序中,我们执行以下操作
Private Sub ImageCarousel_Initialized(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Initialized
AddHandler CarouselTimer.Tick, AddressOf CarouselTimer_Tick
CarouselTimer.Interval = New TimeSpan(0, 0, 0, 0, 100)
ImageGrid_1.RenderTransform = GridScaleTr_1
ImageGrid_2.RenderTransform = GridScaleTr_2
ImageGrid_3.RenderTransform = GridScaleTr_3
ImageGrid_4.RenderTransform = GridScaleTr_4
ImageGrid_5.RenderTransform = GridScaleTr_5
' Increase the scale of the Grid in the middle
' of the UserControl.
Dim y As Double = Canvas.GetTop(ImageGrid_3)
MidCanvasX = CarouselCanvas.ActualWidth / 2
GridScaleTr_3.ScaleX = scale
GridScaleTr_3.ScaleY = scale
GridScaleTr_3.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_3.CenterY = y + (ImgGridHeight / 2)
ChangeImagesOpacity()
End Sub
在上面的方法中,调用了一个名为 ChangeImagesOpacity
的方法。此方法将 UserControl
中所有图片的透明度更改为 60%,除了中间的 Grid
控件之外。
Private Sub ChangeImagesOpacity()
For Each ImgGrid As Grid In CarouselCanvas.Children
If Canvas.GetLeft(ImgGrid) <> 270 Then
For Each el As UIElement In ImgGrid.Children
If TypeOf (el) Is Image Then
el.Opacity = 0.6
End If
Next
ElseIf Canvas.GetLeft(ImgGrid) = 270 Then
For Each el As UIElement In ImgGrid.Children
If TypeOf (el) Is Image Then
el.Opacity = 1
End If
Next
End If
Next
End Sub
当用户按下鼠标左键,开始移动图片的过程时,将调用 UserControl
的 CarouselCanvas
MouseLeftButtonDown
事件处理程序。
Private Sub CarouselCanvas_MouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles CarouselCanvas.MouseLeftButtonDown
If IsCarouseling = False Then
InitMouseX = e.GetPosition(CarouselCanvas).X
InitMouseY = e.GetPosition(CarouselCanvas).Y
End If
End Sub
当用户释放鼠标左键时,会发生以下情况
Private Sub CarouselCanvas_MouseLeftButtonUp(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles CarouselCanvas.MouseLeftButtonUp
If IsCarouseling = False Then
IsCarouseling = True
FinalMouseX = e.GetPosition(CarouselCanvas).X
FinalMouseY = e.GetPosition(CarouselCanvas).Y
DiffX = FinalMouseX - InitMouseX
DiffY = FinalMouseY - InitMouseY
' Check whether swipe is horizontal.
If Math.Abs(DiffX) > Math.Abs(DiffY) Then
CarouselTimer.Start()
Else
IsCarouseling = False
End If
End If
End Sub
如果用户在水平方向移动鼠标,则启动 CarouselTimer
,在其 Tick
事件期间,我们执行以下操作
Private Sub CarouselTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
If move <> 135 Then
MoveImageGrids()
move += shift
ChangeImagesOpacity()
Else
CarouselTimer.Stop()
move = 0
IsCarouseling = False
End If
End Sub
上面调用的 MoveImageGrids
方法会导致 Grid
的最终移动
Private Sub MoveImageGrids()
' Right swipe.
If DiffX > 0 Then
For Each ImgGrid As Grid In CarouselCanvas.Children
Dim x As Double = Canvas.GetLeft(ImgGrid)
Canvas.SetLeft(ImgGrid, (x + shift))
RightCheckOriginals(ImgGrid)
RghtCheckCopy1s(ImgGrid)
RghtCheckCopy2s(ImgGrid)
ScaleUpGrid(ImgGrid)
ScaleGridToNormal(ImgGrid)
Next
Else
' Left swipe.
For Each ImgGrid As Grid In CarouselCanvas.Children
Dim x As Double = Canvas.GetLeft(ImgGrid)
Canvas.SetLeft(ImgGrid, (x - shift))
LeftCheckOriginals(ImgGrid)
LeftCheckCopy1s(ImgGrid)
LeftCheckCopy2s(ImgGrid)
ScaleUpGrid(ImgGrid)
ScaleGridToNormal(ImgGrid)
Next
End If
End Sub
注意:将一个 Grid
移动到下一个最终位置需要 900 毫秒。
RightCheckOriginals
方法检查主 Grid
中最后一个 Grid
的 x 坐标是否到达了 CarouselCanvas
的右边缘,并相应地放置 Grid
。
' Set the location of main ImageGrids to zero
' when their x-position reaches right-edge of canvas.
Private Sub RightCheckOriginals(ByVal ImgGrid As Grid)
If (ImgGrid Is ImageGrid_1) Or (ImgGrid Is ImageGrid_2) _
Or (ImgGrid Is ImageGrid_3) Or (ImgGrid Is ImageGrid_4) _
Or (ImgGrid Is ImageGrid_5) Then
If Canvas.GetLeft(ImgGrid) >= 675 Then
Canvas.SetLeft(ImgGrid, 0)
End If
End If
End Sub
RghtCheckCopy1s
和 RghtCheckCopy2s
方法也执行类似的操作,但这次是针对分别位于主 Grid
左侧和右侧的 Grid
。
' Set the location of ImageGrids on left side
' of the main ImageGrids to -675 when their x-position
' reaches zero.
Private Sub RghtCheckCopy1s(ByVal ImgGrid As Grid)
If (ImgGrid Is ImageGrid_1_Copy1) Or (ImgGrid Is ImageGrid_2_Copy1) _
Or (ImgGrid Is ImageGrid_3_Copy1) Or (ImgGrid Is ImageGrid_4_Copy1) _
Or (ImgGrid Is ImageGrid_5_Copy1) Then
If Canvas.GetLeft(ImgGrid) >= 0 Then
Canvas.SetLeft(ImgGrid, -675)
End If
End If
End Sub
' Place the ImageGrids on the right of the main
' grids to the appropriate location when one of
' those Grids exceeds a certain limit.
Private Sub RghtCheckCopy2s(ByVal ImgGrid As Grid)
If (ImgGrid Is ImageGrid_1_Copy2) Or (ImgGrid Is ImageGrid_2_Copy2) _
Or (ImgGrid Is ImageGrid_3_Copy2) Or (ImgGrid Is ImageGrid_4_Copy2) _
Or (ImgGrid Is ImageGrid_5_Copy2) Then
If Canvas.GetLeft(ImgGrid) >= 1350 Then
Canvas.SetLeft(ImgGrid, 675)
End If
End If
End Sub
还记得我之前说过我会解释为什么我们需要额外的 Grid
吗?好吧,额外的 Grid
存在是为了创建一种错觉,即当 Grid
移动时,最后一张或第一张图片会逐渐出现在 UserControl
的另一端。例如,如果用户将图片向右拖动,最后一张图片似乎会从左端滑出。
ScaleUpGrid
方法(由 MoveImageGrids
调用)会增加 UserControl
中间 Grid
的缩放比例。
' Increase the scale of the Grid in the middle.
Private Sub ScaleUpGrid(ByVal ImgGrid As Grid)
Dim x As Double = Canvas.GetLeft(ImgGrid)
Dim y As Double = Canvas.GetTop(ImgGrid)
If (ImgGrid Is ImageGrid_1) And x = 270 Then
GridScaleTr_1.ScaleX = scale
GridScaleTr_1.ScaleY = scale
GridScaleTr_1.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_1.CenterY = y + (ImgGridHeight / 2)
ElseIf (ImgGrid Is ImageGrid_2) And x = 270 Then
GridScaleTr_2.ScaleX = scale
GridScaleTr_2.ScaleY = scale
GridScaleTr_2.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_2.CenterY = y + (ImgGridHeight / 2)
ElseIf (ImgGrid Is ImageGrid_3) And x = 270 Then
GridScaleTr_3.ScaleX = scale
GridScaleTr_3.ScaleY = scale
GridScaleTr_3.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_3.CenterY = y + (ImgGridHeight / 2)
ElseIf (ImgGrid Is ImageGrid_4) And x = 270 Then
GridScaleTr_4.ScaleX = scale
GridScaleTr_4.ScaleY = scale
GridScaleTr_4.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_4.CenterY = y + (ImgGridHeight / 2)
ElseIf (ImgGrid Is ImageGrid_5) And x = 270 Then
GridScaleTr_5.ScaleX = scale
GridScaleTr_5.ScaleY = scale
GridScaleTr_5.CenterX = MidCanvasX + (ImgGridWidth / 2)
GridScaleTr_5.CenterY = y + (ImgGridHeight / 2)
End If
End Sub
在 Expression Blend 中,如果你选择 UserControl
并查看属性面板的杂项部分,你将注意到有五个属性用于设置 UserControl
的图片。
以下是用于创建其中一个 DependencyProperty
以使之成为可能的代码
Public Property Image1Source() As ImageSource
Get
Return CType(GetValue(Image1Property), ImageSource)
End Get
Set(ByVal value As ImageSource)
SetValue(Image1Property, value)
End Set
End Property
Public Shared Image1Property As DependencyProperty = _
DependencyProperty.Register("Image1Source", _
GetType(ImageSource), _
GetType(ImageCarousel), _
New FrameworkPropertyMetadata( _
New PropertyChangedCallback(AddressOf ChangeSource1)))
Private Shared Sub ChangeSource1(ByVal source As DependencyObject, _
ByVal e As DependencyPropertyChangedEventArgs)
CType(source, ImageCarousel).Image_1.Source = CType(e.NewValue, ImageSource)
CType(source, ImageCarousel).Image_1_Copy1.Source = CType(e.NewValue, ImageSource)
CType(source, ImageCarousel).Image_1_Copy2.Source = CType(e.NewValue, ImageSource)
End Sub
结论
希望你喜欢阅读这篇文章,并获得了一些有用的东西。这只是我使用 Expression Blend 和 WPF 的一些尝试,希望你也能这样做。干杯!
历史
- 2011年3月15日:首次发布