I need to know when a ListBox has finished rendering for the first time so that I can scroll it to the top to present the user with the first item on the list.
I have a ListBox that uses RichTextBox in it’s DataTemplate:
<DataTemplate x:Key="HelpTextTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
...
<ContentControl>
...
<RichTextBox x:Name="HelpTextContent" Grid.Row="1"
Tag="{Binding Path=HelpObject.Text, Mode=TwoWay}"
TextWrapping="Wrap"
HorizontalAlignment="Stretch"
Margin="0,0,20,0"
Loaded="RichTextBox_Loaded"
ContentChanged="RichTextBox_ContentChanged"
SelectionChanged="RichTextBox_SelectionChanged"/>
...
</ContentControl>
...
</Grid>
</DataTemplate>
The ListBox is bound to an ObservableCollection.
I had a problem with the scrolling of the ListBox – if height of the RichTextBox was greater than that of the ListBox the user couldn’t scroll to the bottom of the RichTextBox. The ListBox would jump to the next item in the list. The height of the scroll bar’s slider would change as well. This is because the actual height of the RichTextBox is only calculated when it’s actually rendered. When it’s off the screen the height reverts to smaller value (I think the code assumes that the text can all fit on a single line rather than having to be wrapped).
I tracked these problems down to the ListBox‘s use of a VirtualisingStackPanel to draw the items. When I replaced that with a simple StackPanel those problems went away.
This then created the problem I have now which is that the ListBox scrolls to the bottom of the list on initial load. The Loaded and LayoutUpdated events on the ListBox occur before the data has been loaded. I tried listening out for the PropertyChanged event on the view model when the ObservableCollection is initialised:
void editViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ListDataSource":
// Try to scroll to the top of the ListBox
break;
}
}
this fires too early as well. The list is rendered after this event is fired and causes the ListBox to scroll to the bottom.
In the end I had to use a kludge:
If anyone knows a better way please post your answer now.