问题
I was hoping to collapse certain ListBoxItems based on a property of their data context.
I came up with the following (trimmed for brevity)
<ListBox ItemsSource="{Binding SourceColumns}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsDeleted}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center" Margin="5,0" Text="{Binding ColumnName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This "works" in that it does collapse the listboxitems that are marked as "IsDeleted", however the vertical scrollbar does not adjust for the "missing" items. As I'm scrolling, all of a sudden the bar gets bigger and bigger (without moving) until I scroll past the point of the hidden items, and then finally starts to move.
I also tried explicitly setting the height and width to 0 as well in the data trigger, to no avail.
Does anyone know if there's a workaround for this?
回答1:
Enter CollectinViewSource
One thing you can do is connect your ListBox to your items through a CollectionViewSource.
What you do is create the collectionViewSource in XAML:
<Window.Resources>
<CollectionViewSource x:Key="cvsItems"/>
</Window.Resources>
Connect to it in your CodeBehind or ViewModel
Dim cvsItems as CollectionViewSource
cvsItems = MyWindow.FindResource("cvsItems")
and set it's source property to your collection of items.
cvsItems.Source = MyItemCollection
Then you can do filtering on it. The collectionViewSource maintains all of the items in the collection, but alters the View of those items based on what you tell it.
Filtering
To filter, create a CollectionView using your CollectionViewSource:
Dim MyCollectionView as CollectionView = cvsItems.View
Next write a filtering function:
Private Function FilterDeleted(ByVal item As Object) As Boolean
Dim MyObj = CType(item, MyObjectType)
If MyObj.Deleted = True Then Return False Else Return True End If
End Function
Finally, write something that makes the magic happen:
MyCollectionView .Filter = New Predicate(Of Object)(AddressOf FilterDeleted)
I usually have checkboxes or Radiobuttons in a hideable expander that lets me change my filtering options back and forth. Those are bound to properties each of which runs the filter function which evaluates all the filters and then returns whether the item should appear or not.
Let me know if this works for you.
Edit:
I almost forgot:
<ListBox ItemsSource="{Binding Source={StaticResource cvsItems}}"/>
回答2:
The answer is to set the VirtualizingStackPanel.IsVirtual="False" in your listbox.
Why don't my listboxitems collapse?
来源:https://stackoverflow.com/questions/6655968/wpf-listboxitem-visibility-and-scrollbar