Skip to content

Commit

Permalink
Wpf: Maintain focus of Tree/GridView after ReloadItem/ReloadData
Browse files Browse the repository at this point in the history
  • Loading branch information
cwensley committed Apr 2, 2024
1 parent 398327f commit bbc87c5
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 12 deletions.
16 changes: 8 additions & 8 deletions src/Eto.WinForms/CustomControls/TreeController.cs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ namespace Eto.CustomControls
public interface ITreeHandler
{
ITreeGridItem SelectedItem { get; }
void SelectRow (int row);
void SelectRow(int row);
bool AllowMultipleSelection { get; }

void PreResetTree ();
void PostResetTree ();
bool PreResetTree(object item = null, int row = -1);
void PostResetTree(object item = null, int row = -1);
}

public class TreeController : ITreeGridStore<ITreeGridItem>, IList, INotifyCollectionChanged
Expand Down Expand Up @@ -316,20 +316,20 @@ bool ChildIsSelected (ITreeGridItem item)

void ResetCollection ()
{
if (parent == null)
Handler.PreResetTree ();
OnTriggerCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset));
if (parent == null)
Handler.PostResetTree ();
var doPost = parent == null && Handler.PreResetTree();
OnTriggerCollectionChanged(new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset));
if (doPost) Handler.PostResetTree ();
}

public void ReloadItem(ITreeGridItem item)
{
var row = IndexOf(item);
if (row < 0)
return;
var doPost = parent == null && Handler.PreResetTree(item, row);
OnTriggerCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, row));
OnTriggerCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, row));
if (doPost) Handler.PostResetTree(item, row);
}

public bool CollapseRow (int row)
Expand Down
5 changes: 3 additions & 2 deletions src/Eto.WinForms/Forms/Controls/TreeGridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,12 @@ void AutoSizeColumns(bool displayedOnly)
}
}

void ITreeHandler.PreResetTree()
bool ITreeHandler.PreResetTree(object item, int row)
{
return false;
}

void ITreeHandler.PostResetTree()
void ITreeHandler.PostResetTree(object item, int row)
{
}

Expand Down
8 changes: 8 additions & 0 deletions src/Eto.Wpf/Forms/Controls/GridHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,15 @@ public BorderType Border

public void ReloadData(IEnumerable<int> rows)
{
SkipSelectionChanged = true;
SaveFocus();

Control.Items.Refresh();

DisableAutoScrollToSelection = true;
RestoreFocus();
SkipSelectionChanged = false;
DisableAutoScrollToSelection = false;
}

swc.DataGridRow GetCurrentRow()
Expand Down
7 changes: 5 additions & 2 deletions src/Eto.Wpf/Forms/Controls/TreeGridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,16 @@ public override sw.FrameworkElement SetupCell(IGridColumnHandler column, sw.Fram
return new TreeTogglePanel(defaultContent, controller);
}

void ITreeHandler.PreResetTree()
bool ITreeHandler.PreResetTree(object item, int row)
{
if (item != null && Control.CurrentItem != item)
return false;
SkipSelectionChanged = true;
SaveFocus();
return true;
}

void ITreeHandler.PostResetTree()
void ITreeHandler.PostResetTree(object item, int row)
{
DisableAutoScrollToSelection = true;
RestoreFocus();
Expand Down
85 changes: 85 additions & 0 deletions test/Eto.Test/UnitTests/Forms/Controls/GridTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,5 +491,90 @@ public void AutoSizedColumnShouldChangeSizeOfControl(string text, int rows, int
return layout;
});
}

[Test]
public void ReloadingFocusedItemShouldKeepFocus()
{
bool? hasFocusBefore = null;
bool? hasFocusAfter = null;
Form(form => {
var grid = new T();
grid.ShowHeader = false;
grid.Size = new Size(200, 200);
grid.Columns.Add(new GridColumn { DataCell = new TextBoxCell { Binding = Binding.Property((GridTestItem m) => m.Text) } });
var dataStore = CreateDataStore();
var list = (IList)dataStore;
SetDataStore(grid, dataStore);
grid.SelectedRow = 1;
form.Content = grid;
var gv = grid as GridView;
var tgv = grid as TreeGridView;
form.Shown += async (s, e) =>
{
grid.Focus();
await Task.Delay(TimeSpan.FromSeconds(0.1));
// first, reload an row that doesn't have focus
gv?.ReloadData(0);
tgv?.ReloadItem((ITreeGridItem)list[0]);
await Task.Delay(TimeSpan.FromSeconds(0.1));
// We should still have focus, then reload the item that does have focus
hasFocusBefore = grid.HasFocus;
gv?.ReloadData(1);
tgv?.ReloadItem((ITreeGridItem)list[1]);
await Task.Delay(TimeSpan.FromSeconds(0.1));
// Focus should still be kept
hasFocusAfter = grid.HasFocus;
form.Close();
};
});
Assert.IsTrue(hasFocusBefore, "Grid did not have focus before reloading");
Assert.IsTrue(hasFocusAfter, "Grid did not have focus after reloading");
}

[Test]
public void ReloadingDataShouldKeepFocus()
{
bool? hasFocusBefore = null;
bool? hasFocusAfter = null;
Form(form => {
var grid = new T();
grid.ShowHeader = false;
grid.Size = new Size(200, 200);
grid.Columns.Add(new GridColumn { DataCell = new TextBoxCell { Binding = Binding.Property((GridTestItem m) => m.Text) } });
var dataStore = CreateDataStore();
var list = (IList)dataStore;
SetDataStore(grid, dataStore);
grid.SelectedRow = 1;
form.Content = grid;
var gv = grid as GridView;
var tgv = grid as TreeGridView;
form.Shown += async (s, e) =>
{
grid.Focus();
await Task.Delay(TimeSpan.FromSeconds(0.1));
// We should still have focus, then reload the data
hasFocusBefore = grid.HasFocus;
gv?.ReloadData(Enumerable.Range(0, list.Count));
tgv?.ReloadData();
await Task.Delay(TimeSpan.FromSeconds(0.1));
// Focus should still be kept
hasFocusAfter = grid.HasFocus;
form.Close();
};
});
Assert.IsTrue(hasFocusBefore, "Grid did not have focus before reloading");
Assert.IsTrue(hasFocusAfter, "Grid did not have focus after reloading");
}
}
}

0 comments on commit bbc87c5

Please sign in to comment.