[英]WPF ScrollViewer with ListBox
需要你的幫助。 我有一個ListBox(帶虛擬化 ),顯示ScrollViewer。 我的ListBox項目是可擴展的,並且在擴展時它們的高度可能超過可見滾動區域。
我正在解決的問題是,當列表框項超出可見滾動區域時 - 滾動跳轉到下一個ListBox項而不是簡單地滾動視圖。
檢查此代碼:
<ListBox Grid.Row="1" Grid.Column="0" DataContext="{Binding SpecPackageSpecGroupListViewModel}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"
ItemContainerStyle="{StaticResource SpecPackageSpecGroupListBoxStyle}" ScrollViewer.IsDeferredScrollingEnabled="True"
ItemsSource="{Binding SortedChildren}" ScrollViewer.CanContentScroll="True"
Background="Transparent"
BorderThickness="0" SelectionMode="Extended"
Margin="5,5,5,5">
<ListBox.ItemTemplate>
<DataTemplate>
<Controls:SpecPackageSpecGroupControl/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
當然,我不能用另一個滾動條包裝我的ListBox,因為它會關閉可視化(這對我來說非常無能)。
如果我將CanContentScroll設置為False,一切都按預期工作 - 但虛擬化停止工作。
救命!!!
吉利
好吧,就在我即將放棄並以某種方式學習如何忍受這個錯誤之前我碰到了一個帖子(我現在似乎無法找到),這表明TreeView確實支持基於像素的滾動(AKA物理滾動) )沒有關閉可視化。
所以我嘗試了這一點,確實 - 它有效! 確保驗證虛擬化是否正常工作,使用~1000項進行測試,並在我的控件構造函數上設置斷點,並確保在滾動視圖時調用它。
使用TreeView而不是ListBox的唯一缺點是TreeView似乎不支持多項選擇(我需要) - 但實現這一點比實現ListBox的智能滾動要容易得多。
我為TreeViewItem創建了一個樣式,使TreeViewItem的外觀和行為與ListBoxItem一樣,這實際上並不是強制性的 - 但我喜歡這樣(除了基本樣式有拉伸問題,我必須用樣式修復)。 基本上我刪除了ItemsPresenter並僅使用ContentPresenter,因為我的數據不是分層的:
<Style x:Key="MyTreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Border Name="myBorder"
SnapsToDevicePixels="true"
CornerRadius="0,0,0,0"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
BorderThickness="0"
BorderBrush="Transparent"
Height="Auto"
Margin="1,1,1,3"
Background="Transparent">
<ContentPresenter Grid.Column="1" x:Name="PART_Header" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
現在 - 我唯一要做的就是實現多選樹視圖。 可能有不同的方法來實現這種行為,我采用了ViewModel方法。
從TreeView派生我創建了一個新的MultiSelectionTreeView:
public class MultiSelectionTreeView : TreeView
{
private static bool CtrlPressed
{
get
{
return Keyboard.IsKeyDown(Key.LeftCtrl);
}
}
protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
{
base.OnSelectedItemChanged(e);
var previouseItemViewModel = e.OldValue as IMultiSelectionTreeViewItemViewModel;
if (previouseItemViewModel != null)
{
if (!CtrlPressed)
previouseItemViewModel.IsSelected = false;
}
var newItemViewModel = e.NewValue as IMultiSelectionTreeViewItemViewModel;
if (newItemViewModel != null)
{
if (!CtrlPressed)
newItemViewModel.ClearSelectedSiblings();
newItemViewModel.IsSelected = true;
}
}
}
其中IMultiSelectionTreeViewItemViewModel如下:
public interface IMultiSelectionTreeViewItemViewModel
{
bool IsSelected { get; set; }
void ClearSelectedSiblings();
}
當然 - 現在我有責任處理所選項目的呈現方式 - 在我的情況下,它是由於我的樹視圖項目有自己的DataTemplate,它有選擇的指示。 如果不是這種情況並且您需要它,只需根據其視圖模型IsSelected屬性擴展樹視圖項數據模板以指示其選擇狀態。
希望有一天這會幫助某人:-)玩得開心!
吉利
這個問題仍在搜索引擎中出現,所以我會在2年后回答它。
WPF 4.5現在支持基於像素的虛擬化面板。
如果你可以定位4.5,那么只需將其添加到ListBox:
<Setter Property="VirtualizingPanel.ScrollUnit" Value="Pixel"/>
有關.NET 4.5中的新功能(包括WPF 4.5中的新內容),請參閱http://msdn.microsoft.com/en-us/library/ms171868.aspx
看看這里(Bea Stollnitz)和這里(Dan Crevier) ; 基本上你需要實現自己的容器,支持虛擬化和基於像素的滾動。 您還可以查看此類似的SO問題以獲取更多詳細信息或可能的替代方案。 從VirtualizingStackPanel派生並修改滾動行為似乎是最好的選擇。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.