はじめに
WPFでUWPのTimePickerを作ってみようとしたが、無限に循環するスクロールが標準コントロールになかったので、UserControlで作成してみることにした。
実装
CirculationScroll.xaml
<UserControl>
<UserControl.Resources>
<Storyboard x:Key="storyboardSlideDown" Completed="SlideDown_Completed">
<DoubleAnimation
Storyboard.TargetName="scrollItems"
Storyboard.TargetProperty="(Canvas.Top)"
From="-20"
To="0"
Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="storyboardSlideUp" Completed="SlideUp_Completed">
<DoubleAnimation
Storyboard.TargetName="scrollItems"
Storyboard.TargetProperty="(Canvas.Top)"
From="-20"
To="-40"
Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="storyboardSlideReset">
<DoubleAnimation
Storyboard.TargetName="scrollItems"
Storyboard.TargetProperty="(Canvas.Top)"
To="-20"
Duration="0:0:0" />
</Storyboard>
</UserControl.Resources>
<Grid ClipToBounds="True">
<Canvas x:Name="slideCanvas" ClipToBounds="True">
<ItemsControl
x:Name="scrollItems"
Canvas.Top="-20"
ItemsSource="{Binding ScrollList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:CirculationScroll}}, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
Height="20"
Text="{Binding Text, Mode=TwoWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
</UserControl>
UserControl.Resourcesでスクロールっぽく見せるためのStoryBoardを用意。表示するテキストはItemsControlにTextBlockを用意する。
CirculationScroll.xaml.cs
public partial class CirculationScroll : UserControl
{
public CirculationScroll()
{
InitializeComponent();
ScrollList = new ObservableCollection<ScrollText>();
}
public readonly static DependencyProperty ScrollListProperty = DependencyProperty.Register("ScrollList", typeof(ObservableCollection<ScrollText>), typeof(CirculationScroll), new FrameworkPropertyMetadata(default(ObservableCollection<ScrollText>), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public ObservableCollection<ScrollText> ScrollList
{
get { return (ObservableCollection<ScrollText>)GetValue(ScrollListProperty); }
set { SetValue(ScrollListProperty, value); }
}
private void SlideDown_Completed(object sender, EventArgs e)
{
var reset = FindResource("storyboardSlideReset") as Storyboard;
reset.Begin();
ScrollList.Move(ScrollList.Count - 1, 0);
}
private void SlideUp_Completed(object sender, EventArgs e)
{
var reset = FindResource("storyboardSlideReset") as Storyboard;
reset.Begin();
ScrollList.Move(0, ScrollList.Count - 1);
}
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
var slideDown = FindResource("storyboardSlideDown") as Storyboard;
slideDown.Begin();
}
else
{
var SlideUp = FindResource("storyboardSlideUp") as Storyboard;
SlideUp.Begin();
}
base.OnMouseWheel(e);
}
}
public class ScrollText
{
public ScrollText(string text)
{
Text = text;
}
public string Text { get; set; }
}
依存関係プロパティにObservableCollectionを公開し、ユーザー側で表示文字列のListを設定することで、スクロールっぽくアニメーションできることを確認した。連続的にスクロールした場合にカクつくので改良が必要と思う。