7

StackPanel を使用して、いくつかのコントロールを垂直にレイアウトしています (つまり、タイトル、サブタイトル、リストボックス、セパレーター、リストボックスなど)。

StackPanel は ScrollViewer の子であり、コンテンツが常にスクロール可能であることを保証します。

StackPanel のコントロールの 1 つは ListBox です。

その ItemsSource は巨大なコレクションにバインドされたデータであり、複雑な DataTemplate を使用して各アイテムを実現します。

残念ながら、それを使用するとパフォーマンスが非常に低下します (CPU/メモリが高い)。

私は試した

  • ListBox の ItemsPanel を VirtualizingStackPanel に設定し、
  • その ControlTemplate を ItemsPresenter のみにオーバーライドします (ListBox の ScrollViewer を削除します)。

しかし、パフォーマンスに違いはありませんでした。StackPanel は、測定中に内部の子に無限の高さを与えると思いますか?

ScrollViewer と StackPanel を他のパネル/レイアウト (Grid、DockPanel など) に置き換えたところ、パフォーマンスが大幅に向上したため、ボトルネックと解決策は仮想化にあると思いました。

このビューの CPU/メモリ パフォーマンスを改善する方法はありますか?

ここに画像の説明を入力

【アップデート1】

元のサンプル プロジェクト: http://s000.tinyupload.com/index.php?file_id=29810707815310047536

【アップデート2】

次の例を考え出すために、TreeView/TreeViewItems のスタイル変更/テンプレート化を試みました。起動にまだ時間がかかる/同じで、メモリ使用量が多い。しかし、一度読み込まれると、スクロールは元のサンプルよりもはるかに反応が良くなります.

起動時間/メモリ使用量をさらに改善する他の方法があるかどうか疑問に思いますか?

TreeView プロジェクトのスタイルを変更: http://s000.tinyupload.com/index.php?file_id=00117351345725628185

【アップデート2】

pushprajのソリューションは魅力のように機能します

  • オリジナル:
    • 起動:35秒、
    • メモリ: 393MB
    • スクロール: 遅い
  • ツリー表示:
    • スタートアップ:18代、
    • メモリー 377MB、
    • スクロール: 高速
  • pushpraj のソリューション:
    • 起動: <1 秒、
    • メモリ: 20MB、
    • スクロール: 高速
4

1 に答える 1

19

巨大なリスト ボックスの最大サイズを制限して有効にすることができます。Virtualization

例えば

<ListBox MaxHeight="500" 
         VirtualizingPanel.IsVirtualizing="true" 
         VirtualizingPanel.VirtualizationMode="Recycling" />

これにより、ListBox がいくつかのアイテムのみをロードできるようになり、リストボックスのスクロールバーが必要に応じて残りのアイテムまでスクロールできるようになります。

同時に に設定VirtualizationModeするRecyclingと、複雑なデータ テンプレートを再利用できるため、アイテムごとにテンプレートを再作成する必要がなくなります。


編集

これがあなたのサンプルに基づく解決策です。私は目的を達成するために使用CompositeCollectionしました。Virtualization

xaml

<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:l="clr-namespace:PerfTest">
    <Grid.Resources>
        <DataTemplate DataType="{x:Type l:Permission}">
            <StackPanel Orientation="Horizontal">
                <CheckBox />
                <TextBlock Text="{Binding Name}" />
                <Button Content="+" />
                <Button Content="-" />
                <Button Content="..." />
            </StackPanel>
        </DataTemplate>
        <CompositeCollection x:Key="data">
            <!-- Content 1 -->
            <TextBlock Text="Title"
                       FontSize="24"
                       FontWeight="Thin" />
            <!-- Content 2 -->
            <TextBlock Text="Subtitle"
                       FontSize="16"
                       FontWeight="Thin" />
            <!-- Content 3 -->
            <CollectionContainer Collection="{Binding DataContext, Source={x:Reference listbox}}" />
            <!-- Content 4 -->
            <TextBlock Text="User must scroll past the entire list box before seeing this"
                       FontSize="16"
                       FontWeight="Thin"
                       Padding="5"
                       TextWrapping="Wrap"
                       Background="#99000000"
                       Foreground="White" />
        </CompositeCollection>
    </Grid.Resources>
    <ListBox x:Name="listbox"
             VirtualizingPanel.IsVirtualizing="True"
             VirtualizingPanel.VirtualizationMode="Recycling"
             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
             ItemsSource="{StaticResource data}" />
</Grid>

コード

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var items = new ObservableCollection<Permission>();
        foreach (var i in Enumerable.Range(0, 10000).Select(i => new Permission() { Name = "Permission " + i }))
        { items.Add(i); }
        DataContext = items;
    }
}

public class Permission
{
    public string Name { get; set; }
}

文字列のデータ テンプレートを作成できないため、文字列コレクションをPermissionコレクションに変更しました。あなたの実際のプロジェクトでは、それが似たようなものになることを願っています。

これを試して、これが必要なものに近いかどうかを確認してください。

注:デザイナーの警告がある場合は無視しても問題ありませんCollection="{Binding DataContext, Source={x:Reference listbox}}"

于 2014-08-27T14:56:08.220 に答える