Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion src/EVEMon/SkillPlanner/PlanEditorControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,10 @@ private void UpdateSkillList()
// Disable autorefresh timer, it will be enabled if a training entry is found
tmrAutoRefresh.Stop();

// Stores selection and focus, to restore them after the update
// Stores selection, focus, and scroll position, to restore them after the update
Dictionary<int, bool> selection = StoreSelection();
int focusedHashCode = lvSkills.FocusedItem?.Tag.GetHashCode() ?? 0;
int topItemHash = lvSkills.TopItem?.Tag?.GetHashCode() ?? 0;

lvSkills.BeginUpdate();
try
Expand Down Expand Up @@ -459,6 +460,11 @@ private void UpdateSkillList()
{
lvSkills.EndUpdate();
}

// Restore scroll position AFTER EndUpdate — TopItem uses LVM_SCROLL which is
// ignored while WM_SETREDRAW is FALSE (i.e. inside BeginUpdate/EndUpdate), so
// it must be set here once the control is fully ready to accept scroll commands.
RestoreScrollPosition(topItemHash);
}

/// <summary>
Expand Down Expand Up @@ -783,6 +789,12 @@ private static string GetColumnTextForItem(PlanEntry entry, PlanColumn column, s
private void UpdateListColumns()
{
m_isUpdatingColumns = true;

// Capture scroll position before BeginUpdate/Items.Clear can affect it.
// Must be outside the BeginUpdate block because TopItem restoration (below)
// also needs to happen outside BeginUpdate for the same reason.
int topItemHash = lvSkills.TopItem?.Tag?.GetHashCode() ?? 0;

lvSkills.BeginUpdate();

try
Expand Down Expand Up @@ -819,6 +831,10 @@ private void UpdateListColumns()
lvSkills.EndUpdate();
m_isUpdatingColumns = false;
}

// Re-apply scroll position after this method's own EndUpdate for the same
// reason as in UpdateSkillList: LVM_SCROLL is suppressed inside BeginUpdate.
RestoreScrollPosition(topItemHash);
}

/// <summary>
Expand All @@ -838,6 +854,24 @@ private Dictionary<int, bool> StoreSelection()
return c;
}

/// <summary>
/// Restores the scroll position to the item whose tag hash matches <paramref name="topItemHash"/>.
/// Must be called after <see cref="ListView.EndUpdate"/> — the underlying LVM_SCROLL message is
/// suppressed while WM_SETREDRAW is FALSE (i.e. inside a BeginUpdate/EndUpdate block).
/// </summary>
/// <param name="topItemHash">Hash code of the item to restore as the top visible row, or 0 to skip.</param>
private void RestoreScrollPosition(int topItemHash)
{
if (topItemHash == 0)
return;

ListViewItem topItem = lvSkills.Items.Cast<ListViewItem>()
.FirstOrDefault(x => x.Tag?.GetHashCode() == topItemHash);

if (topItem != null)
lvSkills.TopItem = topItem;
}

/// <summary>
/// Restores the selection from a dictionary where keys are tags' hash codes.
/// </summary>
Expand Down