11

ItemsControlアイテムを に表示し、仮想ScrollViewer化を行う があります。私はそれScrollViewerを含む(オフスクリーン、したがって仮想化された)アイテムにスクロールしようとしています。ただし、アイテムは仮想化されているため、実際には画面上に存在せず、位置もありません (IIUC)。

子要素を試してみBringIntoViewましたが、スクロールして表示されません。TransformToAncestorまた、 、 、TransformBoundsおよびを使用して手動で実行しようとしましScrollToVerticalOffsetたが、TransformToAncestor決して返されません (仮想化のために、位置がないためだと思いますが、その証拠はありません) と、実行されない後のコード。

仮想化を使用してアイテムにスクロールすることは可能ItemsControlですか? もしそうなら、どのように?

4

5 に答える 5

20

しばらくの間、項目にス​​クロールするために 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() やその他の通常のスクロール メソッドを呼び出してアイテムを回避することもできることに注意してください。

于 2012-11-28T04:11:21.460 に答える
9

.NET ソース コードを調べてみると、aListBoxとそのScrollIntoViewメソッドの使用をお勧めします。このメソッドの実装は、そのインデックスでアイテムを強制的に作成してスクロールするinternalなど、いくつかのメソッドに依存しています。VirtualizingPanel.BringIndexIntoViewこれらのメカニズムの多くが内部的なものであるという事実は、これを自分でやろうとすると、うまくいかないことを意味します

(これにより選択が非表示になるようにするには、 を再テンプレート化できますListBoxItems

于 2012-08-25T20:59:41.167 に答える
7

これが古いスレッドであることは知っていますが、他の誰か (私のような) がそれに遭遇した場合に備えて、私が発見したばかりの更新された回答の価値があると考えました.

.NET Framework 4.5 の時点で、ピクセル ベースのスクロールを含め、魅力的に機能VirtualizingPanelする publicメソッドがあります。BringIndexIntoViewPublicをサブクラス化するか、 をItemsControl使用しVisualTreeHelperてその子を見つける必要がありますが、どちらの方法でも、特定のアイテム/インデックスに正確にスクロールVirtualizingPanelするように強制するのは非常に簡単です。ItemsControl

于 2018-11-27T20:58:38.890 に答える
1

私はパーティーにかなり遅れていることを知っていますが、これが解決策を探している他の誰かの助けになることを願っています...

int index = myItemsControl.Items.IndexOf(*your item*).FirstOrDefault();
int rowHeight = *height of your rows*;
myScrollView.ScrollToVerticalOffset(index*rowHeight);
//this will bring the given item to the top of the scrollViewer window

...そして私のXAMLはこのように設定されています...

<ScrollViewer x:Name="myScrollView">
    <ItemsControl x:Name="myItemsControl">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <!-- data here -->
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>
于 2015-03-17T18:53:22.407 に答える