2010-06-17 80 views
12

我有一個解決方案,其中i根據用戶標準產生一個數據網格(或多個實例)..每個網格保持接收數據,因爲它通過的ObservableCollectionWPF數據網格:CanContentScroll屬性引起奇怪的行爲

問題我有進來,這是滾動的怪異。它不穩定,滾動條會在滾動時自行調整大小。

比我發現.. CanContentScroll property!它完全修復了奇怪的滾動行爲,給我帶來了臨時的幸福和快樂。

但是,它會導致2個不幸的副作用。

  1. 每當我重新創建網格實例並將其綁定到我觀察到的集合,它凍結了我的整個窗口,持續5秒。當我的網格增長到一個很大的尺寸時,這個延遲可能持續30秒。

  2. 當我調用TradeGrid.ScrollIntoView(TradeGrid.Items(TradeGrid.Items.Count - 1))滾動到底部時,它跳到底部並且返回頂部。

是否有另一種方法來實現平滑滾動也許?

回答

36

您正遇到滾動的物理滾動和邏輯之間的差異。

正如你所發現的,每一個都有其折衷。

物理滾動

物理滾動(CanContentScroll = FALSE)只是像素得好,所以:

  • 視口始終表示正是您的滾動程度的相同部分,給你一個平滑滾動經驗和

  • DataGrid的全部內容必須完全應用所有模板並進行測量和排列,以確定滾動條的大小,從而導致加載過程中的長時間延遲和高RAM使用率,並且它不會真的滾動項目所以它不理解ScrollIntoView很好

邏輯滾動

邏輯滾動(CanContentScroll =真)計算其滾動視口,並通過程度的項目,而不是像素,因此:

  • 視口可能顯示不同的數目在不同的時間項,與項中的程度的數目意在視口中的項目的數目而變化,從而引起滾動條長度發生變化,並

  • 滾動從一個項目移至之間的下一個,決不,導致「幹」滾動

  • 只要你在底層使用VirtualizingStackPanel,它只需要應用模板並測量和排列目前實際可見的項目,而且ScrollIntoView更簡單,因爲它只需要獲取權項指標進入視野

他們

之間進行選擇,這些都是隻有兩種由WPF提供滾動的。您必須根據上述折衷選擇它們。一般來說,邏輯滾動對於大中型數據集來說是最好的,而物理滾動對於小型數據集來說是最好的。

在物理滾動過程中加速加載的一個技巧是讓物理滾動更好是將您的項目包裝在具有固定大小的自定義裝飾器中,並在其不可見時將其子項的可見性設置爲隱藏。這可以防止ApplyTemplate,Measure和Arrange發生在該項目的後代控件上,直到您準備好實現它。

使物理滾動的ScrollIntoView更可靠的一個竅門是調用它兩次:一次立即,一次在DispatcherPriority.ApplicationIdle的調度程序回調中。

決策邏輯滾動滾動條更穩定

如果所有的項目都具有相同的高度,在任何時間視口中可見將保持不變的項目數,造成滾動拇指大小保持不變(因爲如果項目沒有改變,則與總數的比率)。

也可以修改ScrollBar本身的行爲,以便拇指始終計算爲固定大小。要做到這一點,沒有任何哈克後臺代碼:

  • 子類跟蹤與自己
  • 更改用於邏輯滾動滾動條來使用你的子類的滾動條的模板,以取代在的MeasureOverride拇指位置和大小的計算跟蹤常規one
  • 變化,而不是的ScrollViewer模板明確設置您的自定義滾動條的模板上的邏輯滾動滾動條(而不是使用默認的模板)
  • 更改列表框模板使用顯式上設置自定義的ScrollViewer模板它創建的ScrollViewer

這意味着複製大量的模板代碼從內置的WPF模板,所以它不是一個非常優雅的解決方案。但是替代方案是使用hacky代碼隱藏來等待所有模板展開,然後找到ScrollBar,並將ScrollBar模板替換爲使用自定義Track的ScrollBar模板。此代碼以一些非常棘手的代碼爲代價保存兩個大型模板(ListBox,ScrollViewer)。

使用不同的面板將是一個更大的工作量:VirtualizingStackPanel是唯一的虛擬化面板,只有它和StackPanel才能進行邏輯滾動。由於您正在利用VirtualizingStackPanel的虛擬化功能,因此您必須重新實現所有這些功能以及所有IScrollInfo信息功能以及常規Panel功能。我可以做這樣的事情,但我會分配幾個,也許很多天來讓它正確。我建議你不要嘗試。

+0

非常感謝。 什麼我可以做,使滾動條的大小在邏輯滾動更穩定?也許使用不同的滾動容器等。 – 2010-06-17 14:49:54

+1

有三種選擇可以改善這種情況:調整項目高度,重新模板ListBox/ScrollViewer/ScrollBar以使用自定義Track控件,或編寫自己的虛擬化面板。我已經將所有這三個細節都添加到了答案中。 – 2010-06-17 15:42:35

+0

廢話..我試圖把你的答案再一次,但是這只是刪除了我的初始UP ..如果你編輯你的答案,我將能夠重新申請:) – 2010-06-17 18:10:47

2

我也有同樣的問題,我的DataGrid和最後我做到:

ScrollViewer.CanContentScroll="True" 
EnableRowVirtualization="True" 
VirtualizingPanel.VirtualizationMode="Standard" 

現在一切都在我的DataGrid工作的罰款。

+0

沒有設置VirtualizingPanel.VirtualizationMode,我發現性能更好。將其設置爲「回收」會導致滾動(強制滾動條在物理上滾動)並設置爲「標準」以某種方式導致滾動較慢,這很奇怪,因爲我認爲默認值爲「標準」,但給它一個明確的設置滯後滾動。不明白爲什麼。 – KMC 2017-06-06 12:16:07