How to invalidate layout of listbox from custom children
I have a custom panel for a listbox
<ItemsPanelTemplate x:Key="FloatPanelTemplate">
<Controls:FloatPanel x:Name="CardPanel" />
</ItemsPanelTemplate>
The panel lays out its children using its X and Y dependency properties. This all works nicely when the FloatPanel is used by itself - I'm using FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure on the dependency开发者_高级运维 properties of the child items to tell the FloatPanel to redraw its layout.
When I use it in a Listbox (code above) then it draws fine the first time, but when I drag the children (which modifies the item's X and Y) it is not notifying the Listbox that it needs to redraw the FloatPanel's children. I think the issue is related to the fact that each item in the bound collection is wrapped with a ListBoxItem.
Hopefully I've described what i'm doing well enough that someone can tell me how to make the panel (or its children) tell it needs to do the Layout routines again. As I said it works once (initial draw) but then dragging items doesn't work (Listbox isnt aware that its children have changed and needs to relayout.) If I drag an item and then resize the window, the listbox does a layout and the items are drawn in their new locations.
How do I notify the ListBox (or more importantly the FloatPanel in the ItemsPanelTemplate) that it needs to do a Layout pass?
Instead try FrameworkPropertyMetadataOptions.AffectsParentMeasure and FrameworkPropertyMetadataOptions.AffectsParentArrange.
Those names... Thank God for intellisense, huh?
As you've noted, since ListBoxItem is your element's immediate layout parent, changes to the dependency properties that affect the parent's layout will not be "seen" by the panel which is further up the visual tree.
So instead what you may need to do unfortunately is to traverse the visual tree until you find an element deriving from Panel and call its InvalidateArrange method.
DependencyObject obj=this;
while ( (obj=VisualTreeHelper.GetParent(obj)) != null) {
Panel p = obj as Panel;
if (p != null) {
p.InvalidateArrange();
break;
}
}
It's ugly, but maybe a WPF guru will have a better suggestion.
Are you sure that your ListBox
or ListView
panel isn't seeming to present an incorrect size because it has...
ScrollViewer.CanContentScroll="True"
...which is the default value?
When list control is in this mode, and when it is scrolled to the bottom, there may be extra whitespace at the bottom of its panel in order to make sure that an integral item is lined up at the top of its internal ScrollViewer
, and this might seem like the ScrollViewer
--and hence the list control--is not resizing itself.
To prevent whitespace at the bottom of the panel, you must enable pixel-wise scrolling on the ListBox or ListView control:
ScrollViewer.CanContentScroll="False"
or in code:
ScrollViewer.SetCanContentScroll(list_ctrl, false);
See also: WPF ListView non integral scrolling
精彩评论