I have a ListBox which is not virtualizing. I am obviously missing something, but cannot find it.
It's actually a ListBox within a ListBox. The outer ListBox has an ItemTemplate which contains an Expander. The Expander is used to display a group of items. The content of the Expander is the second ListBox which displays the items. The ItemTemplate on the second ListBox is bound to the actual Item to display. The ViewModel class for my items has a number of properties which do not initialize data until the property Get is called. However, WPF is walking through every item and causing initialization logic, which I'm trying to avoid.
I discovered that using the ListCollectionView.GroupDescription causes a ListBox to not Virtualize. Now I am handling my own grouping in the ViewModel. My outer ListBox is bound to an ObservableCollection(ItemGroupViewModel), where ItemGroupViewModel has a GroupName and a list of Items. The second ListBox is bound to the Items in the ItemGroupViewModel. This did not fix the problem. I also checked VirtualizingStackPanel.GetIsVirtualizing() while debugging and it returns true, but WPF is still walking through every item. I've double checked to ensure my grouping logic does not fire off the data initialization logic in each item, which I'm trying to avoid.
I thought the IsSharedSizeScope could cause the ListBox to render all items in order to determine column sizing. So I turned SharedSizeScope off. Still no virtualization.
What am I missing?
It is not virtualizing because it is inside an expander, the expander's template is a headeredcontentcontrol (as far as I remember), and it's template contains a stackpanel.
Contents of stackpanel can never have alignement stretch in the direction it is stacking, so your listbox will always have all the room it asks for, and then you get no virtualization. Your inner listbox won't get any verticalscrollbar either.
You have one solution (at least :)
1: Set maxheight on your inner listbox - probably the easiest.
Hope it helps :)
Related
I'm having a problem with a TreeView in WPF C#.
I have a TreeView with two TreeViewItems defined in XAML.
On the second TreeViewItem, I have a list of items defined by a binding.
When the list is too long, a vertical scrollbar appears and allows the entire TreeView to scroll.
But the two TreeViewItems must stay at the same place, so I'd like the content of the second to scroll instead, rather than the entire TreeView.
Left : what I get, and the two first items are scrolled out; Right what I'd like, with the two first items staying at the same spot. (The scrollbar is the red zone).
I look forward to hearing from you guys, and thanks in advance,
Raekh.
EDIT :
Found a solution : I removed the two treeviewitems and used a treeview with a item source obtained by binding, so the treeview starts after the treeviewitems and is scrolled properly.
That might be a silly question, but I just can figure how to resolve it for now.
I'm building a wpf application with drag and drop between a ListView and a Grid.
My items being consituted by an Image and a TextBlock. I have defined a DataTemplate with a StackPanel containing these controls and applied it to ListView items and ContentControls inside of the Grid cells.
Basic idea is to chose items from the ListView and drag them to a cell. So my grid is empty at the beginning.
My problem, besides of sucking at making my controls filling correctly my grid (bonus ninja question !), is that when no item is chosen in a cell the image is not drawn and will not act as drop target. Only the TextBlock will.
Is there a way to counter that ? Thank you :)
You can set a datatemplate trigger so that you display an empty image that will accept the drop, if the contents are null.
And if that idea doesn't work, you can create a datatemplateselector that returns a template with a blank dropping target if the content is null. This shows how to make a selector that can let you set all possible templates using only xaml.
I have a ScrollViewer and a ListBox inside it which is bound to an ObservableCollection in the view model. The ScrollViewer is maximized to take up all available space of the parent container. I'm finding that when the collection is modified and ends up producing more ListBoxItems than can fit in the viewable area of the ScrollViewer, the ScrollViewer scrolls down to show the last item in the ListBox. How do I prevent the ScrollViewer from scrolling when the child ListBox's items are updated?
I would like the scroll position to stay intact whenever the collection in the view model is updated.
Thanks in advance!
You are going to have to manage this yourself. The ListBox has a ScrollIntoView method that allows you to scroll to a specific location:
http://msdn.microsoft.com/en-us/library/system.windows.controls.listbox.scrollintoview(v=VS.95).aspx
Determining the items that are currently visible, if you need this, is not so easy. See the ItemsControlExtensions that I wrote as part of the WP7Contrib project:
http://wp7contrib.codeplex.com/SourceControl/changeset/view/67473#1475881
This has a GetItemsInView extensions method that will provide the list of visible items.
I have a ListBox that contains a number of User items that are DataTemplated to appear as UserControls in the ListBox. Each UserControl can be expanded in size. To start with, the ListBox is big enough to display them all in their unexpanded state. The problem that I have is that when a number of these UserControls are expanded together, they extend out of the ListBox's visible area. The ListBox does not recognise this fact and no ScrollBars appear, even when they are set to Visible.
I am using DoubleAnimations to alter the UserControl heights when the user clicks on a button in each one. Is there something that I have to do, or some setting on the ListBox that must be set to get it to register the size changes of the UserControls that represent its items and display ScrollBars when needed?
Edit>>>
I have tracked down the problem to a custom WrapPanel that I am using in the ListBox.ItemsPanel. When I remove it, or replace it with a standard WrapPanel, ScrollBars appear when required. I got the code for the Panel from a good article about creating custom WPF panels. Can anyone see what's missing from the code given in the article and why it might stop the ScrollBars from displaying?
I wonder whether ListBoxes normally do what you are expecting? You might try calling InvalidateMeasure/Layout on the ListBox if you know when the item sizes change, just to see?
I decided to write the custom WrapPanel code again completely and this time it worked correctly! When comparing the new version with the previous version, I could see that a + was missing from a += in a measuring calculation and so the Panel thought that the items were much smaller than they really were... hence no ScrollBars.
So, if you have this problem, check your measuring code carefully.
Listbox has the style in which itemtemplate consists of expander and inside expander there is a one more listbox, listbox inside the expander has to be accessed. So how to go ahead?
What data does the inner list box contain? Does your outer object contain a list of child objects as a property? If so, bind the inner listbox's ItemsSource to that property.
If you want to access the listbox from code, this is probably what you're looking for: How to: Find DataTemplate-Generated Elements. It shows how to traverse the visual tree to find the generated elements. Using the visual tree is not a good solution usually though, so consider using data binding instead if at all possible.