|
|
|
@ -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; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridColumn" /> 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<DataGridLength>).NewValue.Value; |
|
|
|
if (grid != null) |
|
|
|
{ |
|
|
|
var oldWidth = (change as AvaloniaPropertyChangedEventArgs<DataGridLength>).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<DataGridLength> WidthProperty = AvaloniaProperty |
|
|
|
.Register<DataGridColumn, DataGridLength>(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); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -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.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="source"></param>
|
|
|
|
/// <param name="width">The DataGridLength to coerce.</param>
|
|
|
|
/// <returns>The resultant (coerced) DataGridLength.</returns>
|
|
|
|
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 |
|
|
|
/// </summary>
|
|
|
|
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.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="value">The new Value.</param>
|
|
|
|
/// <param name="unitType">The new UnitType.</param>
|
|
|
|
/// <param name="desiredValue">The new DesiredValue.</param>
|
|
|
|
/// <param name="displayValue">The new DisplayValue.</param>
|
|
|
|
/// <param name="oldWidth">with before resize.</param>
|
|
|
|
/// <param name="newWidth">with after resize.</param>
|
|
|
|
/// <param name="userInitiated">Whether or not this resize was initiated by a user action.</param>
|
|
|
|
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 |
|
|
|
/// <param name="width">The new Width.</param>
|
|
|
|
internal void SetWidthInternalNoCallback(DataGridLength width) |
|
|
|
{ |
|
|
|
_width = width; |
|
|
|
var originalValue = _setWidthInternalNoCallback; |
|
|
|
_setWidthInternalNoCallback = true; |
|
|
|
try |
|
|
|
{ |
|
|
|
Width = width; |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
_setWidthInternalNoCallback = originalValue; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -1122,7 +1143,7 @@ namespace Avalonia.Controls |
|
|
|
&& OwningGrid.DataConnection != null |
|
|
|
&& OwningGrid.DataConnection.SortDescriptions != null) |
|
|
|
{ |
|
|
|
if(CustomSortComparer != null) |
|
|
|
if (CustomSortComparer != null) |
|
|
|
{ |
|
|
|
return |
|
|
|
OwningGrid.DataConnection.SortDescriptions |
|
|
|
|