From ea580c71619331b2d6eebefd203138151c519c3f Mon Sep 17 00:00:00 2001 From: sdoroff Date: Wed, 3 Mar 2021 23:47:06 -0500 Subject: [PATCH 1/4] DataGridCheckBoxColumn Edit Fix --- .../DataGridCheckBoxColumn.cs | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs index e2a067ac61..179abd4b63 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs @@ -153,23 +153,7 @@ namespace Avalonia.Controls { if (editingElement is CheckBox editingCheckBox) { - bool? uneditedValue = editingCheckBox.IsChecked; - bool editValue = false; - if(editingEventArgs is PointerPressedEventArgs args) - { - // Editing was triggered by a mouse click - Point position = args.GetPosition(editingCheckBox); - Rect rect = new Rect(0, 0, editingCheckBox.Bounds.Width, editingCheckBox.Bounds.Height); - editValue = rect.Contains(position); - } - else if (_beganEditWithKeyboard) - { - // Editing began by a user pressing spacebar - editValue = true; - _beganEditWithKeyboard = false; - } - - if (editValue) + void EditValue() { // User clicked the checkbox itself or pressed space, let's toggle the IsChecked value if (editingCheckBox.IsThreeState) @@ -192,6 +176,46 @@ namespace Avalonia.Controls editingCheckBox.IsChecked = !editingCheckBox.IsChecked; } } + + bool? uneditedValue = editingCheckBox.IsChecked; + if(editingEventArgs is PointerPressedEventArgs args) + { + void ProcessPointerArgs() + { + // Editing was triggered by a mouse click + Point position = args.GetPosition(editingCheckBox); + Rect rect = new Rect(0, 0, editingCheckBox.Bounds.Width, editingCheckBox.Bounds.Height); + if(rect.Contains(position)) + { + EditValue(); + } + } + + void OnLayoutUpdated(object sender, EventArgs e) + { + if(!editingCheckBox.Bounds.IsEmpty) + { + editingCheckBox.LayoutUpdated -= OnLayoutUpdated; + ProcessPointerArgs(); + } + } + + if(editingCheckBox.Bounds.IsEmpty) + { + editingCheckBox.LayoutUpdated += OnLayoutUpdated; + } + else + { + ProcessPointerArgs(); + } + } + else if (_beganEditWithKeyboard) + { + // Editing began by a user pressing spacebar + _beganEditWithKeyboard = false; + EditValue(); + } + return uneditedValue; } return false; From 4cb94f351192c634435b5687d39360e9d3350f16 Mon Sep 17 00:00:00 2001 From: sdoroff Date: Fri, 12 Mar 2021 12:53:17 -0500 Subject: [PATCH 2/4] Fixed SharedSizeGroup Layout Bug --- src/Avalonia.Controls/DefinitionBase.cs | 77 ++++++++++++++++++------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index 38ebbe5bf9..3237f6f37b 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -662,31 +662,64 @@ namespace Avalonia.Controls { DefinitionBase definitionBase = _registry[i]; - if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) + // we'll set d.UseSharedMinimum to maintain the invariant: + // d.UseSharedMinimum iff d._minSize < this.MinSize + // i.e. iff d is not a "long-pole" definition. + // + // Measure/Arrange of d's Grid uses d._minSize for long-pole + // definitions, and max(d._minSize, shared size) for + // short-pole definitions. This distinction allows us to react + // to changes in "long-pole-ness" more efficiently and correctly, + // by avoiding remeasures when a long-pole definition changes. + bool useSharedMinimum = !MathUtilities.AreClose(definitionBase._minSize, sharedMinSize); + + // before doing that, determine whether d's Grid needs to be remeasured. + // It's important _not_ to remeasure if the last measure is still + // valid, otherwise infinite loops are possible + bool measureIsValid; + + if(!definitionBase.UseSharedMinimum) { - // if definition's min size is different, then need to re-measure - if (!MathUtilities.AreClose(sharedMinSize, definitionBase.MinSize)) - { - Grid parentGrid = (Grid)definitionBase.Parent; - parentGrid.InvalidateMeasure(); - definitionBase.UseSharedMinimum = true; - } - else - { - definitionBase.UseSharedMinimum = false; - - // if measure is valid then also need to check arrange. - // Note: definitionBase.SizeCache is volatile but at this point - // it contains up-to-date final size - if (!MathUtilities.AreClose(sharedMinSize, definitionBase.SizeCache)) - { - Grid parentGrid = (Grid)definitionBase.Parent; - parentGrid.InvalidateArrange(); - } - } + // d was a long-pole. measure is valid iff it's still a long-pole, + // since previous measure didn't use shared size. + measureIsValid = !useSharedMinimum; + } + else if(useSharedMinimum) + { + // d was a short-pole, and still is. measure is valid + // iff the shared size didn't change + measureIsValid = !sharedMinSizeChanged; + } + else + { + // d was a short-pole, but is now a long-pole. This can + // happen in several ways: + // a. d's minSize increased to or past the old shared size + // b. other long-pole definitions decreased, leaving + // d as the new winner + // In the former case, the measure is valid - it used + // d's new larger minSize. In the latter case, the + // measure is invalid - it used the old shared size, + // which is larger than d's (possibly changed) minSize + measureIsValid = (definitionBase.LayoutWasUpdated && + MathUtilities.GreaterThanOrClose(definitionBase._minSize, this.MinSize)); + } - definitionBase.LayoutWasUpdated = false; + if(!measureIsValid) + { + definitionBase.Parent.InvalidateMeasure(); } + else if (!MathUtilities.AreClose(sharedMinSize, definitionBase.SizeCache)) + { + // if measure is valid then also need to check arrange. + // Note: definitionBase.SizeCache is volatile but at this point + // it contains up-to-date final size + definitionBase.Parent.InvalidateArrange(); + } + + // now we can restore the invariant, and clear the layout flag + definitionBase.UseSharedMinimum = useSharedMinimum; + definitionBase.LayoutWasUpdated = false; } _minSize = sharedMinSize; From b48e7fe432fe9c461d54c3509e6a75845e3d427b Mon Sep 17 00:00:00 2001 From: sdoroff Date: Fri, 12 Mar 2021 13:45:34 -0500 Subject: [PATCH 3/4] Fix Keyboard Handling --- .../DataGridCheckBoxColumn.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs index 179abd4b63..3a3cb3bb68 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs @@ -17,7 +17,6 @@ namespace Avalonia.Controls /// public class DataGridCheckBoxColumn : DataGridBoundColumn { - private bool _beganEditWithKeyboard; private CheckBox _currentCheckBox; private DataGrid _owningGrid; @@ -173,6 +172,7 @@ namespace Avalonia.Controls } else { + System.Diagnostics.Debug.WriteLine($"InitialValue: {editingCheckBox.IsChecked}"); editingCheckBox.IsChecked = !editingCheckBox.IsChecked; } } @@ -209,12 +209,6 @@ namespace Avalonia.Controls ProcessPointerArgs(); } } - else if (_beganEditWithKeyboard) - { - // Editing began by a user pressing spacebar - _beganEditWithKeyboard = false; - EditValue(); - } return uneditedValue; } @@ -308,13 +302,10 @@ namespace Avalonia.Controls CheckBox checkBox = GetCellContent(row) as CheckBox; if (checkBox == _currentCheckBox) { - _beganEditWithKeyboard = true; OwningGrid.BeginEdit(); - return; } } } - _beganEditWithKeyboard = false; } private void OwningGrid_LoadingRow(object sender, DataGridRowEventArgs e) From 0db62855b48d3baf716d231683b120e1d20b2f1d Mon Sep 17 00:00:00 2001 From: sdoroff Date: Fri, 12 Mar 2021 14:42:07 -0500 Subject: [PATCH 4/4] Remove Print Line --- src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs index 3a3cb3bb68..ccf1f3f77a 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs @@ -172,7 +172,6 @@ namespace Avalonia.Controls } else { - System.Diagnostics.Debug.WriteLine($"InitialValue: {editingCheckBox.IsChecked}"); editingCheckBox.IsChecked = !editingCheckBox.IsChecked; } }