views:

8209

answers:

6

WPF, Browserlike app.
I got one page containing a ListView. After calling a PageFunction I add a line to the ListView, and want to scroll the new line into view:

  ListViewItem item = ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
  if (item != null)
    ScrollIntoView(item);

This works. As long as the new line is in view the line gets the focus like it should.

Problem is, things don't work when the line is not visible.
If the line is not visible, there is no ListViewItem for the line generated, so ItemContainerGenerator.ContainerFromIndex returns null.

But without the item, how do I scroll the line into view? Is there any way to scroll to the last line (or anywhere) without needing an ListViewItem?

+2  A: 
EFrank
Tried the code, it works. Not nice, but an answer. I'd like to clean up my question to reflect the real problem, if you want to include the code (links might change) I'd mark you as answer.
Sam
Since it works I marked you as answer anyway - but I still think it would be nice if the code is copied here, in case the link changes.
Sam
+1  A: 

One workaround to this is to change the ItemsPanel of the ListView. The default panel is the VirtualizingStackPanel which only creates the ListBoxItem the first time they become visible. If you don't have too many items in your list, it should not be a problem.

<ListView>
   ...
   <ListView.ItemsPanel>
      <ItemsPanelTemplate>
         <StackPanel/>
      </ItemsPanelTemplate>
   </ListView.ItemsPanel>
</ListView>
decasteljau
+16  A: 

Someone told me an even better way to scroll to a specific line, which is easy and works like charm.
In short:

public void ScrollToLastItem()
{
  lv.SelectedItem = lv.Items.GetItemAt(rows.Count - 1);
  lv.ScrollIntoView(lv.SelectedItem);
  ListViewItem item = lv.ItemContainerGenerator.ContainerFromItem(lv.SelectedItem) as ListViewItem;
  item.Focus();
}

The longer version in MSDN forums:

Sam
ScrollIntoView works - thx
Jeffrey
The only problem with this for me is that it callously overrides any selection the user might have made already. Still, should be an easy enough modification to make, so +1 for you, sir, thank you.
metao
Oh, yes - for me, changing the selection was exactly what I wanted, but you are right.
Sam
+1  A: 

Thanks for that last tip Sam. I had a dialog which opened, meaning my grid lost focus every time the dialog closed. I use this:

if(currentRow >= 0 && currentRow < lstGrid.Items.Count) {
    lstGrid.SelectedIndex = currentRow;
    lstGrid.ScrollIntoView(lstGrid.SelectedItem);
    if(shouldFocusGrid) {
        ListViewItem item = lstGrid.ItemContainerGenerator.ContainerFromItem(lstGrid.SelectedItem) as ListViewItem;
        item.Focus();
    }
} else if(shouldFocusGrid) {
    lstGrid.Focus();
}
Echilon
+3  A: 

I made some changes to Sam's answer. Note that I wanted to scroll to the last line. Unfortunately the ListView sometiems just displayed the last line (even when there were e.g. 100 lines above it), so this is how I fixed that:

    public void ScrollToLastItem()
    {
        if (_mainViewModel.DisplayedList.Count > 0)
        {
            var listView = myListView;
            listView.SelectedItem = listView.Items.GetItemAt(_mainViewModel.DisplayedList.Count - 1);
            listView.ScrollIntoView(listView.Items[0]);
            listView.ScrollIntoView(listView.SelectedItem);
            //item.Focus();
        }
    }

Cheers

Joseph Melettukunnel
A: 

Try this ` private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { ScrollViewer scrollViewer = GetScrollViewer(lstVw) as ScrollViewer; scrollViewer.ScrollToHorizontalOffset(dataRowToFocus.RowIndex); if (dataRowToFocus.RowIndex < 2) lstVw.ScrollIntoView((Entity)lstVw.Items[0]); else lstVw.ScrollIntoView(e.AddedItems[0]); }

public static DependencyObject GetScrollViewer(DependencyObject o) { if (o is ScrollViewer) { return o; }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
        {
            var child = VisualTreeHelper.GetChild(o, i);

            var result = GetScrollViewer(child);
            if (result == null)
            {
                continue;
            }
            else
            {
                return result;
            }
        }
        return null;
    } 

private void Focus() { lstVw.SelectedIndex = dataRowToFocus.RowIndex; lstVw.SelectedItem = (Entity)dataRowToFocus.Row;

ListViewItem lvi = (ListViewItem)lstVw.ItemContainerGenerator.ContainerFromItem(lstVw.SelectedItem); ContentPresenter contentPresenter = FindVisualChild(lvi); contentPresenter.Focus(); contentPresenter.BringIntoView();

} `

Murali.S