しばらくの間、項目にスクロールするために VirtualizingStackPanel を使用して ItemsControl を取得することを検討してきましたが、「ListBox を使用する」という回答を見つけ続けました。やりたくなかったので、方法を見つけました。最初に、ScrollViewer を含む ItemsControl のコントロール テンプレートをセットアップする必要があります (項目コントロールを使用している場合は、おそらく既に持っています)。私の基本的なテンプレートは次のようになります (ItemsControl の便利なスタイルに含まれています)。
<Style x:Key="TheItemsControlStyle" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False" HorizontalScrollBarVisibility="Auto">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
だから私は基本的に私のコンテンツを含むスクロールビューアとの境界線を持っています.
私のItemsControlは次のように定義されています:
<ItemsControl x:Name="myItemsControl" [..snip..] Style="{DynamicResource TheItemsControlStyle}" ScrollViewer.CanContentScroll="True" VirtualizingStackPanel.IsVirtualizing="True">
さて、楽しい部分です。ItemsControl にアタッチして、指定された項目までスクロールする拡張メソッドを作成しました。
public static void VirtualizedScrollIntoView(this ItemsControl control, object item) {
try {
// this is basically getting a reference to the ScrollViewer defined in the ItemsControl's style (identified above).
// you *could* enumerate over the ItemsControl's children until you hit a scroll viewer, but this is quick and
// dirty!
// First 0 in the GetChild returns the Border from the ControlTemplate, and the second 0 gets the ScrollViewer from
// the Border.
ScrollViewer sv = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild((DependencyObject)control, 0), 0) as ScrollViewer;
// now get the index of the item your passing in
int index = control.Items.IndexOf(item);
if(index != -1) {
// since the scroll viewer is using content scrolling not pixel based scrolling we just tell it to scroll to the index of the item
// and viola! we scroll there!
sv.ScrollToVerticalOffset(index);
}
} catch(Exception ex) {
Debug.WriteLine("What the..." + ex.Message);
}
}
したがって、拡張メソッドを配置すると、ListBox のコンパニオン メソッドと同じように使用できます。
myItemsControl.VirtualizedScrollIntoView(someItemInTheList);
よく働く!
sv.ScrollToEnd() やその他の通常のスクロール メソッドを呼び出してアイテムを回避することもできることに注意してください。