diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
index a5695afeb7..a77ac985ac 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
@@ -7,7 +7,6 @@ using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using Avalonia.Collections;
-using Avalonia.Utilities;
using System;
using System.ComponentModel;
using System.Linq;
@@ -24,8 +23,6 @@ namespace Avalonia.Controls
{
internal const int DATAGRIDCOLUMN_maximumWidth = 65536;
private const bool DATAGRIDCOLUMN_defaultIsReadOnly = false;
-
- private DataGridLength? _width; // Null by default, null means inherit the Width from the DataGrid
private bool? _isReadOnly;
private double? _maxWidth;
private double? _minWidth;
@@ -39,6 +36,7 @@ namespace Avalonia.Controls
private IBinding _clipboardContentBinding;
private ControlTheme _cellTheme;
private Classes _cellStyleClasses;
+ private bool _setWidthInternalNoCallback;
///
/// Initializes a new instance of the class.
@@ -214,6 +212,36 @@ namespace Avalonia.Controls
OwningGrid?.OnColumnVisibleStateChanged(this);
NotifyPropertyChanged(change.Property.Name);
}
+ else if (change.Property == WidthProperty)
+ {
+ if (!_settingWidthInternally)
+ {
+ InheritsWidth = false;
+ }
+ if (_setWidthInternalNoCallback == false)
+ {
+ var grid = OwningGrid;
+ var width = (change as AvaloniaPropertyChangedEventArgs).NewValue.Value;
+ if (grid != null)
+ {
+ var oldWidth = (change as AvaloniaPropertyChangedEventArgs).OldValue.Value;
+ if (width.IsStar != oldWidth.IsStar)
+ {
+ SetWidthInternalNoCallback(width);
+ IsInitialDesiredWidthDetermined = false;
+ grid.OnColumnWidthChanged(this);
+ }
+ else
+ {
+ Resize(oldWidth, width, false);
+ }
+ }
+ else
+ {
+ SetWidthInternalNoCallback(width);
+ }
+ }
+ }
}
@@ -549,48 +577,15 @@ namespace Avalonia.Controls
}
}
+ public static readonly StyledProperty WidthProperty = AvaloniaProperty
+ .Register(nameof(Width)
+ , coerce: CoerceWidth
+ );
+
public DataGridLength Width
{
- get
- {
- return
- _width ??
- OwningGrid?.ColumnWidth ??
- // We don't have a good choice here because we don't want to make this property nullable, see DevDiv Bugs 196581
- DataGridLength.Auto;
- }
- set
- {
- if (!_width.HasValue || _width.Value != value)
- {
- if (!_settingWidthInternally)
- {
- InheritsWidth = false;
- }
-
- if (OwningGrid != null)
- {
- DataGridLength width = CoerceWidth(value);
- if (width.IsStar != Width.IsStar)
- {
- // If a column has changed either from or to a star value, we want to recalculate all
- // star column widths. They are recalculated during Measure based off what the value we set here.
- SetWidthInternalNoCallback(width);
- IsInitialDesiredWidthDetermined = false;
- OwningGrid.OnColumnWidthChanged(this);
- }
- else
- {
- // If a column width's value is simply changing, we resize it (to the right only).
- Resize(width.Value, width.UnitType, width.DesiredValue, width.DisplayValue, false);
- }
- }
- else
- {
- SetWidthInternalNoCallback(value);
- }
- }
- }
+ get => this.GetValue(WidthProperty);
+ set => SetValue(WidthProperty, value);
}
///
@@ -812,19 +807,34 @@ namespace Avalonia.Controls
/// on the rest of the star columns. For pixel widths, the desired value is based on the pixel value.
/// For auto widths, the desired value is initialized as the column's minimum width.
///
+ ///
/// The DataGridLength to coerce.
/// The resultant (coerced) DataGridLength.
- internal DataGridLength CoerceWidth(DataGridLength width)
+ static DataGridLength CoerceWidth(AvaloniaObject source, DataGridLength width)
{
+ var target = (DataGridColumn)source;
+
+ if (target._setWidthInternalNoCallback)
+ {
+ return width;
+ }
+
+ if (!target.IsSet(WidthProperty))
+ {
+
+ return target.OwningGrid?.ColumnWidth ??
+ DataGridLength.Auto;
+ }
+
double desiredValue = width.DesiredValue;
if (double.IsNaN(desiredValue))
{
- if (width.IsStar && OwningGrid != null && OwningGrid.ColumnsInternal != null)
+ if (width.IsStar && target.OwningGrid != null && target.OwningGrid.ColumnsInternal != null)
{
double totalStarValues = 0;
double totalStarDesiredValues = 0;
double totalNonStarDisplayWidths = 0;
- foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetDisplayedColumns(c => c.IsVisible && c != this && !double.IsNaN(c.Width.DesiredValue)))
+ foreach (DataGridColumn column in target.OwningGrid.ColumnsInternal.GetDisplayedColumns(c => c.IsVisible && c != target && !double.IsNaN(c.Width.DesiredValue)))
{
if (column.Width.IsStar)
{
@@ -839,7 +849,7 @@ namespace Avalonia.Controls
if (totalStarValues == 0)
{
// Compute the new star column's desired value based on the available space if there are no other visible star columns
- desiredValue = Math.Max(ActualMinWidth, OwningGrid.CellsWidth - totalNonStarDisplayWidths);
+ desiredValue = Math.Max(target.ActualMinWidth, target.OwningGrid.CellsWidth - totalNonStarDisplayWidths);
}
else
{
@@ -853,7 +863,7 @@ namespace Avalonia.Controls
}
else
{
- desiredValue = ActualMinWidth;
+ desiredValue = target.ActualMinWidth;
}
}
@@ -862,7 +872,7 @@ namespace Avalonia.Controls
{
displayValue = desiredValue;
}
- displayValue = Math.Max(ActualMinWidth, Math.Min(ActualMaxWidth, displayValue));
+ displayValue = Math.Max(target.ActualMinWidth, Math.Min(target.ActualMaxWidth, displayValue));
return new DataGridLength(width.Value, width.UnitType, desiredValue, displayValue);
}
@@ -896,7 +906,7 @@ namespace Avalonia.Controls
};
result[!ContentControl.ContentProperty] = this[!HeaderProperty];
result[!ContentControl.ContentTemplateProperty] = this[!HeaderTemplateProperty];
- if (OwningGrid.ColumnHeaderTheme is {} columnTheme)
+ if (OwningGrid.ColumnHeaderTheme is { } columnTheme)
{
result.SetValue(StyledElement.ThemeProperty, columnTheme, BindingPriority.Template);
}
@@ -909,7 +919,7 @@ namespace Avalonia.Controls
///
internal void EnsureWidth()
{
- SetWidthInternalNoCallback(CoerceWidth(Width));
+ SetWidthInternalNoCallback(CoerceWidth(this, Width));
}
internal Control GenerateElementInternal(DataGridCell cell, object dataItem)
@@ -931,17 +941,17 @@ namespace Avalonia.Controls
/// can only decrease in size by the amount that the columns after it can increase in size.
/// Likewise, the column can only increase in size if other columns can spare the width.
///
- /// The new Value.
- /// The new UnitType.
- /// The new DesiredValue.
- /// The new DisplayValue.
+ /// with before resize.
+ /// with after resize.
/// Whether or not this resize was initiated by a user action.
- internal void Resize(double value, DataGridLengthUnitType unitType, double desiredValue, double displayValue, bool userInitiated)
+
+ // double value, DataGridLengthUnitType unitType, double desiredValue, double displayValue
+ internal void Resize(DataGridLength oldWidth, DataGridLength newWidth, bool userInitiated)
{
- double newValue = value;
- double newDesiredValue = desiredValue;
- double newDisplayValue = Math.Max(ActualMinWidth, Math.Min(ActualMaxWidth, displayValue));
- DataGridLengthUnitType newUnitType = unitType;
+ double newValue = newWidth.Value;
+ double newDesiredValue = newWidth.DesiredValue;
+ double newDisplayValue = Math.Max(ActualMinWidth, Math.Min(ActualMaxWidth, newWidth.DisplayValue));
+ DataGridLengthUnitType newUnitType = newWidth.UnitType;
int starColumnsCount = 0;
double totalDisplayWidth = 0;
@@ -955,11 +965,11 @@ namespace Avalonia.Controls
// If we're using star sizing, we can only resize the column as much as the columns to the
// right will allow (i.e. until they hit their max or min widths).
- if (!hasInfiniteAvailableWidth && (starColumnsCount > 0 || (unitType == DataGridLengthUnitType.Star && Width.IsStar && userInitiated)))
+ if (!hasInfiniteAvailableWidth && (starColumnsCount > 0 || (newUnitType == DataGridLengthUnitType.Star && newWidth.IsStar && userInitiated)))
{
- double limitedDisplayValue = Width.DisplayValue;
+ double limitedDisplayValue = oldWidth.DisplayValue;
double availableIncrease = Math.Max(0, OwningGrid.CellsWidth - totalDisplayWidth);
- double desiredChange = newDisplayValue - Width.DisplayValue;
+ double desiredChange = newDisplayValue - oldWidth.DisplayValue;
if (desiredChange > availableIncrease)
{
// The desired change is greater than the amount of available space,
@@ -979,7 +989,7 @@ namespace Avalonia.Controls
// The desired change is negative, so we need to increase the widths of columns to the right.
limitedDisplayValue += desiredChange + OwningGrid.IncreaseColumnWidths(DisplayIndex + 1, -desiredChange, userInitiated);
}
- if (ActualCanUserResize || (Width.IsStar && !userInitiated))
+ if (ActualCanUserResize || (oldWidth.IsStar && !userInitiated))
{
newDisplayValue = limitedDisplayValue;
}
@@ -1002,9 +1012,10 @@ namespace Avalonia.Controls
}
}
- DataGridLength oldWidth = Width;
- SetWidthInternalNoCallback(new DataGridLength(Math.Min(double.MaxValue, newValue), newUnitType, newDesiredValue, newDisplayValue));
- if (Width != oldWidth)
+ newDisplayValue = Math.Min(double.MaxValue, newValue);
+ newWidth = new DataGridLength(newDisplayValue, newUnitType, newDesiredValue, newDisplayValue);
+ SetWidthInternalNoCallback(newWidth);
+ if (newWidth != oldWidth)
{
OwningGrid.OnColumnWidthChanged(this);
}
@@ -1052,7 +1063,17 @@ namespace Avalonia.Controls
/// The new Width.
internal void SetWidthInternalNoCallback(DataGridLength width)
{
- _width = width;
+ var originalValue = _setWidthInternalNoCallback;
+ _setWidthInternalNoCallback = true;
+ try
+ {
+ Width = width;
+ }
+ finally
+ {
+ _setWidthInternalNoCallback = originalValue;
+ }
+
}
///
@@ -1122,7 +1143,7 @@ namespace Avalonia.Controls
&& OwningGrid.DataConnection != null
&& OwningGrid.DataConnection.SortDescriptions != null)
{
- if(CustomSortComparer != null)
+ if (CustomSortComparer != null)
{
return
OwningGrid.DataConnection.SortDescriptions
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
index 0755864c25..28e8a0ed5e 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
@@ -785,7 +785,9 @@ namespace Avalonia.Controls
double desiredWidth = _originalWidth + mouseDelta;
desiredWidth = Math.Max(_dragColumn.ActualMinWidth, Math.Min(_dragColumn.ActualMaxWidth, desiredWidth));
- _dragColumn.Resize(_dragColumn.Width.Value, _dragColumn.Width.UnitType, _dragColumn.Width.DesiredValue, desiredWidth, true);
+ _dragColumn.Resize(_dragColumn.Width,
+ new(_dragColumn.Width.Value, _dragColumn.Width.UnitType, _dragColumn.Width.DesiredValue, desiredWidth),
+ true);
OwningGrid.UpdateHorizontalOffset(_originalHorizontalOffset);
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
index 4056b78bfe..8dd5bd262b 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
@@ -91,7 +91,10 @@ namespace Avalonia.Controls
// this column is newly added, we'll just set its display value directly.
if (UsesStarSizing && column.IsInitialDesiredWidthDetermined)
{
- column.Resize(column.Width.Value, column.Width.UnitType, desiredWidth, desiredWidth, false);
+ var oldWidth = column.Width;
+ column.Resize(oldWidth,
+ new(column.Width.Value, column.Width.UnitType, desiredWidth, desiredWidth),
+ false);
}
else
{
@@ -142,7 +145,7 @@ namespace Avalonia.Controls
{
Debug.Assert(dataGridColumn != null);
- if (dataGridColumn is DataGridBoundColumn dataGridBoundColumn &&
+ if (dataGridColumn is DataGridBoundColumn dataGridBoundColumn &&
dataGridBoundColumn.Binding is BindingBase binding)
{
var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
@@ -359,6 +362,7 @@ namespace Avalonia.Controls
if (column.IsVisible && oldValue != column.ActualMaxWidth)
{
+ DataGridLength oldWitdh = new(oldValue, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue);
if (column.ActualMaxWidth < column.Width.DisplayValue)
{
// If the maximum width has caused the column to decrease in size, try first to resize
@@ -371,7 +375,9 @@ namespace Avalonia.Controls
{
// If the column was previously limited by its maximum value but has more room now,
// attempt to resize the column to its desired width.
- column.Resize(column.Width.Value, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue, false);
+ column.Resize(oldWitdh,
+ new (column.Width.Value, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue),
+ false);
}
OnColumnWidthChanged(column);
}
@@ -388,6 +394,7 @@ namespace Avalonia.Controls
if (column.IsVisible && oldValue != column.ActualMinWidth)
{
+ DataGridLength oldWitdh = new(oldValue, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue);
if (column.ActualMinWidth > column.Width.DisplayValue)
{
// If the minimum width has caused the column to increase in size, try first to resize
@@ -400,7 +407,9 @@ namespace Avalonia.Controls
{
// If the column was previously limited by its minimum value but but can be smaller now,
// attempt to resize the column to its desired width.
- column.Resize(column.Width.Value, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue, false);
+ column.Resize(oldWitdh,
+ new(column.Width.Value, column.Width.UnitType, column.Width.DesiredValue, column.Width.DesiredValue),
+ false);
}
OnColumnWidthChanged(column);
}
diff --git a/src/Avalonia.Controls.DataGrid/DataGridLength.cs b/src/Avalonia.Controls.DataGrid/DataGridLength.cs
index a193352f52..9bff8b2cf5 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridLength.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridLength.cs
@@ -7,7 +7,6 @@ using Avalonia.Utilities;
using System;
using System.ComponentModel;
using System.Globalization;
-using Avalonia.Controls.Utils;
namespace Avalonia.Controls
{