diff --git a/src/Eto.WinForms/CustomControls/TreeController.cs b/src/Eto.WinForms/CustomControls/TreeController.cs old mode 100644 new mode 100755 index 39f0979c8e..9642d66c54 --- a/src/Eto.WinForms/CustomControls/TreeController.cs +++ b/src/Eto.WinForms/CustomControls/TreeController.cs @@ -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, IList, INotifyCollectionChanged @@ -316,11 +316,9 @@ 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) @@ -328,8 +326,10 @@ 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) diff --git a/src/Eto.WinForms/Forms/Controls/TreeGridViewHandler.cs b/src/Eto.WinForms/Forms/Controls/TreeGridViewHandler.cs index a37c3e0de3..f5e893f52c 100644 --- a/src/Eto.WinForms/Forms/Controls/TreeGridViewHandler.cs +++ b/src/Eto.WinForms/Forms/Controls/TreeGridViewHandler.cs @@ -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) { } diff --git a/src/Eto.Wpf/Forms/Controls/GridHandler.cs b/src/Eto.Wpf/Forms/Controls/GridHandler.cs index 0d0f7e6132..3c0fe6dfe4 100755 --- a/src/Eto.Wpf/Forms/Controls/GridHandler.cs +++ b/src/Eto.Wpf/Forms/Controls/GridHandler.cs @@ -939,7 +939,15 @@ public BorderType Border public void ReloadData(IEnumerable rows) { + SkipSelectionChanged = true; + SaveFocus(); + Control.Items.Refresh(); + + DisableAutoScrollToSelection = true; + RestoreFocus(); + SkipSelectionChanged = false; + DisableAutoScrollToSelection = false; } swc.DataGridRow GetCurrentRow() diff --git a/src/Eto.Wpf/Forms/Controls/TreeGridViewHandler.cs b/src/Eto.Wpf/Forms/Controls/TreeGridViewHandler.cs index 7d6c4f7bd0..9a04084220 100755 --- a/src/Eto.Wpf/Forms/Controls/TreeGridViewHandler.cs +++ b/src/Eto.Wpf/Forms/Controls/TreeGridViewHandler.cs @@ -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(); diff --git a/test/Eto.Test/UnitTests/Forms/Controls/GridTests.cs b/test/Eto.Test/UnitTests/Forms/Controls/GridTests.cs index 21804077b8..5fd00d576f 100644 --- a/test/Eto.Test/UnitTests/Forms/Controls/GridTests.cs +++ b/test/Eto.Test/UnitTests/Forms/Controls/GridTests.cs @@ -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"); + } } }