私が何をしたかをお話しします。おそらくそれで十分だと思います。次の (または前の) 画像にスワイプできるフルスクリーンの画像ビューアーが必要でしたが、通常のスクロールではなく、画像にスナップすることができました。
内部 scrollViewer を無効にしてフルスクリーンの ListBox を使用し (XAML を参照)、添付の依存関係プロパティを使用して、内部 scrollViewer の水平 (および垂直) オフセットのプロパティを取得しました (スクロールを自分でアニメーション化できるようにするため)。画像をズーム (およびパン) したかったので、私の実装はもっと複雑ですが、次の画像に移動するだけの部分は難しくありません。
免責事項: StackOverflow や他のサイトのいくつかのソースからコードを取得しました。どこで手に入れたのかもう覚えていませんが、これらのアイデアはすべて自分で思いついたわけではありません。どこでそれを与えるべきか知っていれば、私は喜んで信用を与えます.
まず、ScrollViewerEx という新しいクラスを作成します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace ImageViewer
{
public class ScrollViewerEx
{
public static double GetHOffset(ScrollViewer obj)
{
return (double)obj.GetValue(ScrollViewer.HorizontalOffsetProperty);
}
public static void SetHOffset(ScrollViewer obj, double value)
{
obj.SetValue(HOffsetProperty, value);
}
// Using a DependencyProperty as the backing store for HOffset. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HOffsetProperty =
DependencyProperty.RegisterAttached("HOffset", typeof(double), typeof(ScrollViewerEx), new PropertyMetadata(new PropertyChangedCallback(OnHOffsetChanged)));
private static void OnHOffsetChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var scroll = sender as ScrollViewer;
scroll.ScrollToHorizontalOffset((double)e.NewValue);
}
public static double GetVOffset(ScrollViewer obj)
{
return (double)obj.GetValue(ScrollViewer.VerticalOffsetProperty);
}
public static void SetVOffset(ScrollViewer obj, double value)
{
obj.SetValue(VOffsetProperty, value);
}
// Using a DependencyProperty as the backing store for VOffset. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VOffsetProperty =
DependencyProperty.RegisterAttached("VOffset", typeof(double), typeof(ScrollViewerEx), new PropertyMetadata(new PropertyChangedCallback(OnVOffsetChanged)));
private static void OnVOffsetChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var scroll = sender as ScrollViewer;
scroll.ScrollToVerticalOffset((double)e.NewValue);
}
}
}
さて、以下のようなリストボックスが用意されているとしましょう。私の場合、Images プロパティは PictureModel というクラスで、内部には ImageSource がありました。私は ItemTemplate を表示していませんが、Image を内部に配置し、Source を ImageSource にバインドするだけです。ListBox の下の Rectangle に注目してください。ズームされた画像を使用していたときに座標系が変化していたため、すべてのタッチコードをそこに置きました。Rectangle オーバーレイを使用すると、すべてのタッチに対して標準の画面座標が得られます。これは必要ないかもしれません。
<ListBox ItemsSource="{Binding Images}"
x:Name="listBox"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.ManipulationMode="Control"
Loaded="listBox_Loaded_1"
>
<ListBox.Resources>
<Storyboard x:Name="ScrollStoryboard">
<DoubleAnimation x:Name="AnimationH" Duration="0:0:0.5">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseInOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation x:Name="AnimationV" Duration="0:0:0.5">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseInOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<StaticResource ResourceKey="ListBoxItemPivotStyle"/>
</ListBox.ItemContainerStyle>
</ListBox>
<Rectangle Fill="Transparent"
x:Name="TouchRectangle"
ManipulationCompleted="Rectangle_ManipulationCompleted_1"
ManipulationDelta="Rectangle_ManipulationDelta_1"
ManipulationStarted="Rectangle_ManipulationStarted_1"/>
わかりました、別のクリティカル セクションです。ページのコンストラクターに THIS を必ず入れてください。これにより、スクロールビューアのオフセットの変更をアニメーション化できます。
Storyboard.SetTargetProperty(ScrollStoryboard.Children[0], new PropertyPath(ScrollViewerEx.HOffsetProperty));
Storyboard.SetTargetProperty(ScrollStoryboard.Children[1], new PropertyPath(ScrollViewerEx.VOffsetProperty));
ListBox 内の scrollviewer への永続的な参照を取得します。
private void listBox_Loaded_1(object sender, RoutedEventArgs e)
{
scrollviewer = GetVisualChild<ScrollViewer>(listBox);
}
最後に、操作イベントを処理します。リストボックスのスクロールをアニメーション化するために重要なのは、操作完了イベントです。垂直オフセットは使用せず、水平オフセットのみを使用しました。変数 vm.Position は、scrollviewer.horizontaloffset に沿って計算された位置です。基本的に、5 番目の画像を使用している場合は、画面幅を 4 倍して水平方向のオフセットを取得します。
private void Rectangle_ManipulationCompleted_1(object sender, ManipulationCompletedEventArgs e)
{
if (e.FinalVelocities.LinearVelocity.X > 2000)
{
if (ScrollStoryboard.GetCurrentState() != ClockState.Stopped)
ScrollStoryboard.Stop(); // ensure storyboard stopped after previous run
AnimationH.SetValue(DoubleAnimation.FromProperty, scrollviewer.HorizontalOffset);
AnimationH.SetValue(DoubleAnimation.ToProperty, (double)vm.Position);
Storyboard.SetTarget(ScrollStoryboard, scrollviewer);
ScrollStoryboard.Begin();
}
}
これが役立つことを願っています。前述したように、私が作成した完全な実装には、ListBox から得られる組み込みの UI 仮想化に加えて、データ仮想化が含まれています。それとズーム。公開する準備が整っていませんが、これで始めることができます。