How do I create a dumped ItemsControl or Panel with a repeating title?
I'm trying to create a Panel or ItemsControl that will display items on a form:
Heading 1
- Subparagraph 1
- Subparagraph 2
- Subparagraph 3
Heading 2
- Subparagraph 1
- Subparagraph 2
It's simple enough, but the catch here is that I need to split the items in Paged mode. Based on the height of the control, anything that doesn't fit will be on the next page (and so on). If splitting occurs between subitems, I need to display the corresponding title again on the next page.
I have made some progress with MeasureOverride and ArrangeOverride, but I keep working in dead ends. This is really frustrating because it is something that is computationally trivial, but a WPF / Silverlight nightmare. If you've ever worked with report packs, the concept is very similar to this.
I keep falling back to not being able to determine the height until I add children to the control (using Dispatcher.BeginInvoke).
Does anyone have any suggestions for this? Thanks in advance!
Edit
[WPF] ObservableCollection and DataTemplate Generation Function in ListBoxItem
This link is very similar to what mdm20 suggested, but I'm still stuck. Every time I try to get ActualHeight, it returns 0. Also, the ItemContainerGenerator in Silverlight 3 returns null for the container if I don't complete the call in the Dispatcher.BeginInvoke operation.
a source to share
If I had to implement this, I don't think I would try to do it in a panel. I think you will need a collection of elements, a header template, a swap template, and an element template. You can get the height of the template using something like this:
Size maxSize = new Size(0, 30);
UIElement templateRoot = template.LoadContent() as UIElement;
templateRoot.Measure(maxSize);
Size size = templateRoot.DesiredSize;
For this, you need to have the height specified in the template. I think you only care about the height, so I left the width at 0.
Once you get the height of the template, you probably have to set up some kind of map that keeps track of which objects are on which page. This will need to be recreated every time you resize or change the source of the elements.
After that, you just need to add the items as children of the panel contained in the control, depending on which page you are on.
This is how I try to do it .. if it makes sense at all :)
a source to share
You can't directly measure UIElement
until you build it, but you can create list items in such a way that you know in advance how much space they will take up. For example, you can use Grid
to position each of the elements with a line of known height (for example headerHeight
) for the heading and lines with a known height for each of the sub-points (for example subitemHeight
). Then you can calculate the height of each element with forumula headerHeight
+ numSubitems
* subitemHeight
. Also, if you know that the number of items will be pretty small, say less than 1000, you can just go ahead and create all of them ahead of time, as the performance penalty might be acceptable at this point.
I agree that this can be annoying, but it is a very flexible framework that poses a problem. This problem of calculating the height is what makes it so difficult to make a smooth scrolling yet virtualized list of items in a ListBox or ListView.
a source to share