4

I have the following page layout in my application:

<Grid x:Name="ContentPanel"
      Grid.Row="1">

  <ScrollViewer x:Name="ScrollViewer1" 
                MaxHeight="600"
                VerticalAlignment="Top"
                HorizontalAlignment="Stretch">

    <StackPanel x:Name="StackPanel1" >
      <TextBlock x:Name="TextBlock1" />

      <toolkit:ListPicker  x:Name="ListPicker1" />

      <TextBlock x:Name="TextBlock2" />

      <TextBox x:Name="TextBlock3" />

      <TextBlock x:Name="TextBlock4" />

      <StackPanel x:Name="StackPanel2" >

        <TextBlock x:Name="TextBlock5" />

        <Image x:Name="Image1"/>

      </StackPanel>

      <ListBox x:Name="ListBox1">
        <!--Customize the ListBox template to remove the built-in ScrollViewer-->
        <ListBox.Template>
          <ControlTemplate>
            <ItemsPresenter />
          </ControlTemplate>
        </ListBox.Template>

        <ListBox.ItemTemplate>
          <DataTemplate>

            <!-- .... -->

          </DataTemplate>
        </ListBox.ItemTemplate>

        <ListBox.ItemContainerStyle>
          <Style TargetType="ListBoxItem">
            <Setter Property="HorizontalContentAlignment"
                    Value="Stretch" />
          </Style>
        </ListBox.ItemContainerStyle>
      </ListBox>

    </StackPanel>

  </ScrollViewer>

</Grid>

I added an external ScrollViewer instead of the using the ListBox's because without it the stuff above the ListBox was taking too much room and not leaving enough space to view the ListBox contents.

Now, the problem is if I add an item to the end of the ListBox the ScrollIntoView method does not work. So I need to use the ScrollViewer's ScrollToVerticalOffset method.

I'm adding the new item to an ObservableCollection that is bound to the ListBox when the user clicks a button on the application bar. How can I calculate the value to be passed to ScrollViewer.ScrollToVerticalOffset?

Thanks for your help!

Praetorian
  • 100,267
  • 15
  • 224
  • 307

1 Answers1

6

You can find the container that the ListBox has generated to host your element. Once you have this container, you can find its position relative to the scrollviewer:

  var newItem = // the item you just added to your listbox

  // find the ListBox container
  listBox.UpdateLayout()
  var element = listBox.ItemContainerGenerator.ContainerFromItem(newItem) as FrameworkElement;

  // find its position in the scroll viewer
  var transform = element.TransformToVisual(ScrollViewer);
  var elementLocation = transform.Transform(new Point(0, 0));
  double newVerticalOffset = elementLocation.Y + ScrollViewer.VerticalOffset;

  // scroll into view
  ScrollViewer.ScrollToVerticalOffset(newVerticalOffset);

Hope that helps

ColinE
  • 64,631
  • 12
  • 149
  • 215
  • Works beautifully! Thank you so much! I did have to use `myListBox.UpdateLayout();` before this code, otherwise `ContainerFromItem()` kept returning `null`. Also, the result of `ContainerFromItem()` needs to be cast to a `ListBoxItem`. – Praetorian Jan 06 '11 at 07:41