问题
Ok, for illustrative purposes, below I created a subclass of ListBoxItem
and a subclass of ListBox
which uses it as its container by overriding both IsItemItsOwnContainerOverride
and GetContainerForItemOverride
.
Now when the window first appears, as expected, MeasureOverride
is called on every ListBoxItem
(with Infinity,Infinity) followed by ArrangeOverride
being called on every item.
However, when resizing the ListBox
, only ArrangeOverride
is called on the ListBoxItem
, not MeasureOverride
even though the metadata for the width property is set to AffectsMeasure
.
NotE: I know I can get around this by setting
ScrollViewer.HorizontalScrollbarVisibility
to 'Disabled' in which caseMeasureOverride
does get called as expected because that scroll setting forces the items to match the width of the listbox and thus naturally would re-fire. However, I'm still trying to figure out why Measure isn't called by default anyway because the metadata for theWidth
property has theAffectsMeasure
flag set and the width is changing via theArrangeOverride
step.
Is that flag just a hint for its container and in the case of a control placed in a ScrollViewer
it's ignored? My guess is that unless you disable the scrolling, the controls have an infinite area available to them, so once they are measured, there's no need to re-measure them again. Disable the horizontal scrolling however and you're stating the width isn't unlimited, hence the MeasureOverride
is called again. But that's just a guess, albeit a logical one.
Here's example code to play with. Create a new WPF project and paste this in the window's CodeBehind and look at the debug output. Next, set the HorizontalScrollbarVisibility flag and you'll see that it does get called.
public partial class MainWindow : Window
{
public MainWindow(){
InitializeComponent();
var items = new List<object>(){ "This is a really, really, really, really long sentence"};
var lbx = new ListBoxEx { ItemsSource = items };
this.Content = lbx;
}
}
public class ListBoxEx : ListBox
{
protected override bool IsItemItsOwnContainerOverride(object item){
return (item is ListBoxItemEx);
}
protected override DependencyObject GetContainerForItemOverride(){
return new ListBoxItemEx();
}
}
public class ListBoxItemEx : ListBoxItem
{
protected override Size MeasureOverride(Size availableSize){
Console.WriteLine("MeasureOverride called with " + availableSize);
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize){
Console.WriteLine("ArrangeOverride called with " + finalSize);
return base.ArrangeOverride(finalSize);
}
}
回答1:
Ok, I think the answer is it's not firing because the Measure pass is affecting the panel, not the items, and the panel itself hasn't resized so there's no reason to re-measure its children.
However, when setting ScrollViewer.HorizontalScrollbarVisibility
to Disabled
, the width of the panel tracks the width of the ListBox, not its contents, therefore the children do need to be re-measured, hence that's why they were in that case.
来源:https://stackoverflow.com/questions/7655632/why-is-a-listboxitem-not-calling-measureoverride-when-its-width-is-changed