12

問題:スクロール可能な領域に大量のデータを表示すると、パフォーマンスやユーザー エクスペリエンスが低下します。

試した:基本的に、ListBox に DataTemplate を設定して、VirtualizationMode を Recycle に設定し、ListBox 自体に固定の高さを設定して、入力されたデータのグリッドを表示します。以下の例のようなもの。

 <ListBox x:Name="Items"
      TabNavigation="Once"
      VirtualizingStackPanel.VirtualizationMode="Recycling"     
      Height="500">         
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="0,5">
                        <HyperlinkButton Content="Action" Margin="5"/>
                        <ContentControl  
                                cal:View.Model="{Binding}"  
                                VerticalContentAlignment="Stretch" 
                                HorizontalContentAlignment="Stretch"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

ContentControl は<Grid>、約 20 の静的な TextBlock と 20 のデータ バインド TextBlock で構成される、入力されたアイテムの全体的なレイアウトをフォーマットする別のビューから標準を取り込みます。

これは問題なく機能し、初期負荷が半分になります。ただし、問題は、高さを固定サイズにしない機能が必要であるため、親で使用可能なスペースを占有し、サイズを変更することもできます。おかげで@DanFox、仮想化を呼び出すには何らかの形で高さを修正する必要があることがわかりました。そうしないと、RenderEngine はとにかく無限の余地があると考えています。

質問は次のとおりです。これを行うためのより良い方法はありますか、または少なくとも現在の手法を修正して、UX を向上させるにはどうすればよいですか? これらのアイテムを数百個生成する可能性があるため、仮想化のパフォーマンス強化が必要です。ただし、ユーザーがウィンドウのサイズを変更し、効果的にスクロールできるようにする必要もあります。

どんな洞察も大歓迎です、ありがとう、ハッピーホリデー!

4

5 に答える 5

1

わかりましたので、これが私がやったことであり、それは大きな改善であると言わざるを得ません! この特定の作品のドットで 77 秒の読み込み時間から始めました。背面のバインド方法をリファクタリングしたことで、約 20 秒短縮されたため、UI レンダリングに問題が残っていました。以下の答えは、私が最初に考えていたよりも明らかに単純であり、今では膨大な量のデータを 15 ~ 20 秒で (もちろん仮想化を使用して) ロードしています。

これが私がしたことです。

 <!-- This needs to be contained in a parent panel like a grid -->
 <ListBox x:Name="Items" >
                <ListBox.Template>
                    <ControlTemplate> <!-- Broke it out to allow resizing -->
                        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                            <ItemsPresenter/> <!-- This little fella does magical things -->            
                        </ScrollViewer>         
                    </ControlTemplate>      
                </ListBox.Template>
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel VirtualizingStackPanel.VirtualizationMode="Recycling"/>  <!-- Recycle was a must -->        
                    </ItemsPanelTemplate>       
                </ListBox.ItemsPanel>
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <HyperlinkButton  VerticalAlignment="Top" Margin="5" />
                                <!-- This guy I did need to set a minwidth on to retain nice and predictable scrolling 
 when datacontext was potentially changing -->
                            <ContentControl cal:View.Model="{Binding}" MinWidth="1160"
                                            VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
                        </StackPanel>
                    </DataTemplate>         
                </ListBox.ItemTemplate>           
            </ListBox>

以上です!出来上がり!ControlTemplate を分割して、直接 ItemsPresenter を適用するだけで済みました。今では素晴らしい仮想化が行われ、サイズが変更され、ユニバースのバランスが回復され、ユニコーンをパンチしたくなくなりました. その後、アイテムを選択する必要がなかったため、視覚的な状態を取り除きました。これで終わりです。皆さんの洞察に感謝します! 申し訳ありませんが、今回は報奨金を授与できませんでした。

于 2012-12-26T17:11:28.807 に答える
1

リクエストに応じて:-)これまでのところ、何も「答えた」気がしませんでした...

あなたは絶対に正しいです、高さを動的にする方法があるはずです。固定の高さに設定することは、仮想化が機能していることを確認するための簡単なチェックです。パフォーマンス プロファイラー、または SilverlightSpy を使用して何かを達成しましたか? UI/VM のバインディングをリファクタリングしてより効率的にすることで、これらの問題の 1 つを解消しました。これには、潜在的に優れたソリューションを備えた WinPhone7 SL の優れたリソースがありました。それを掘り下げることができるかどうかを確認します (理論はフルファット SL に移行する必要があります)。

これは、VM アーキテクチャに応じたキャッシングの良い点です。

これは、laxy loading をもう少し説明するので役に立つかもしれません

そして、WinPho 7 開発チームからのいくつかのヒント。

それが役立つことを願っています

于 2012-12-21T09:57:32.960 に答える
0

高さが固定されているだけの場合は、これを試してみませんか?

<Grid>    
<ListBox x:Name="Items"
      TabNavigation="Once"
      VirtualizingStackPanel.VirtualizationMode="Recycling"     
      Height="{Binding Path=Height,RelativeSource={RelativeSource AncestorType=Grid}}">         
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="0,5">
                        <HyperlinkButton Content="Action" Margin="5"/>
                        <ContentControl  
                                cal:View.Model="{Binding}"  
                                VerticalContentAlignment="Stretch" 
                                HorizontalContentAlignment="Stretch"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
</Grid>

ListBoxを、スタックパネルのように内部空間ではなく外部空間に適合するコンテナに入れることが重要です。

これを試して、それが役立つかどうか教えてください。:)

于 2012-12-21T10:40:18.987 に答える
0

魔法のように UI コントロールをデータ テンプレートに取り込んでいるとしたら、仮想化の目的に反していると思います。これらのコントロール (グリッド) 自体は再利用されていますか? {Binding} が変更されるとどうなりますか? アタッチされたビヘイビアのように見えるもので実行されるコードの量は? おそらく、あなたが行ったことはパフォーマンスを上げることができます。ただし、単純なデータ テンプレートを作成する (または通常の UserControl を配置する) と、その中のすべてのコントロールが再利用され、データ コンテキストを切り替える際のペナルティが最小限になることがわかります。

高さの問題についてはよくわかりません。それは機能するはずです (Arrange で有限の高さを取得します) が、フードの下で何をしているかによって異なります (おそらく、Arrange が高さを使用可能にする前に、すべてを把握しようとしています)。

独自の仮想化項目コントロールをいつでも作成できます。Panel から派生させて ScrollViewer 内に配置し、Panel に IScrollInfo を実装します。そうすれば、物事がそのようになっているすべての理由を知ることができます:)

于 2012-12-21T16:26:06.713 に答える
0

それがあなたのユースケースに受け入れられる解決策であるかどうかはわかりませんがDelayedLayoutUpdateContainer、複雑なレイアウトをラップしてパフォーマンスの向上に役立つという名前の ContentControl を作成しました。DelayedLayoutUpdateContainer の背後にある考え方は、コンテンツのサイズが所定の期間に変更されていない場合にのみコンテンツのサイズを調整するというものです。ControlTemplate 内の ContentPresenter のサイズは絶対値に設定されます。そのため、ListBoxes の高さを絶対値に設定するのと同じ効果があります。

于 2012-12-21T17:01:58.610 に答える