The ListView control provides a ScrollIntoView() method that ensures
the specified item is on screen, scrolling the ListView if needed.
Unfortunately this method is very slow (50-100 ms) and sometimes
fails entirely on larger lists. (Yay WPF.)
Because the ListView is scrolling by fixed-height item, it's possible
to use the underlying ScrollViewer to move the list instantaneously
and reliably. So now we do that.
Also, fixed a bug with select-all, where we weren't clearing the
previous selection before calling SelectAll(), leading to a mismatch
with the secondary data structure that we maintain because WPF
ListViews can't deal with large selections efficiently. (Yay WPF.)
There's still some weird behavior, e.g. sometimes hitting F5 clears
the current selection and sometimes it doesn't. I think it's related
to which item has focus and the fact you're hitting a key; using the
debug menu item doesn't cause the behavior.
Also, increased MAX_SEL_COUNT from 2000 to 5000. That takes about
200ms to restore to a ListView on my 5-year-old system.
Whenever the display list gets regenerated, we need to restore the
code list view scroll position to the previous location in the file.
This gets tricky when multiple lines are appearing or disappearing.
We were saving the file offset of the line, but that works poorly
when there's a multi-line comment associated with that offset,
because we end up scrolling to the top of the comment whenever any
part of the comment is at the top of the screen.
We now track the file offset and the number of lines we were from
the top of that offset's content. This works well unless we remove
a lot of lines. If the adjusted line index would put us into a
different file offset, we punt and just scroll to the top of the item.
Also, fix a crasher in Edit Note.
Also, fix behavior when the list shrinks while a line near the end
of the file is selected.
Also, change a few instances of "Color.FromArgb(0,0,0,0)" to use a
common constant.
Restoring the selection works pretty much like it used to, though
I'm capping the total size of the selection because it goes into
stupid-slow mode if you have too many elements.
Getting the item that is at the top of the ListView is astoundingly
obscure, due to the ListView's extreme generality. I make a
simplifying assumption -- that we're using a VSP -- which allows us
to use a simple vertical offset once we've dug the appropriate
object out of the visual tree. (The alternative is to walk through
the list of items and see what's on screen, or perform a hit test
calculation in the upper left corner.) Yay WPF.
The various items in the Actions menu are enabled or disabled based
on the current selection. There's no SelectedIndices property in
WPF ListViews, so we have to do things slightly differently.
The SelectedItems list isn't kept sorted to match the list contents,
so finding first/last item requires a bit of scanning.
Also, rearranged some stuff. I'm trying to keep the old and new
code somewhat parallel, to make it easier to walk through at the end
and see if I've missed something.
Renamed VirtualListViewSelection to DisplayListSelection, because
it's now tied to the DisplayList implementation. Hooked it up to
handle SelectionChanged events.
Also, tweaked the code list item style to remove the one-pixel gap
between items. Somehow I manage to click on the dead zone with
surprising regularity.