| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- // (c) Copyright Microsoft Corporation.
- // This source is subject to the Microsoft Public License (Ms-PL).
- // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
- // All other rights reserved.
- using Avalonia.Utilities;
- using System;
- using System.ComponentModel;
- using System.Globalization;
- using Avalonia.Controls.Utils;
- namespace Avalonia.Controls
- {
- public enum DataGridLengthUnitType
- {
- Auto = 0,
- Pixel = 1,
- SizeToCells = 2,
- SizeToHeader = 3,
- Star = 4
- }
- /// <summary>
- /// Represents the lengths of elements within the <see cref="T:Avalonia.Controls.DataGrid" /> control.
- /// </summary>
- [TypeConverter(typeof(DataGridLengthConverter))]
- public struct DataGridLength : IEquatable<DataGridLength>
- {
- private double _desiredValue; // desired value storage
- private double _displayValue; // display value storage
- private double _unitValue; // unit value storage
- private DataGridLengthUnitType _unitType; // unit type storage
- // static instances of value invariant DataGridLengths
- private static readonly DataGridLength _auto = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.Auto);
- private static readonly DataGridLength _sizeToCells = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.SizeToCells);
- private static readonly DataGridLength _sizeToHeader = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.SizeToHeader);
- // WPF uses 1.0 as the default value as well
- internal const double DATAGRIDLENGTH_DefaultValue = 1.0;
- /// <summary>
- /// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridLength" /> class.
- /// </summary>
- /// <param name="value"></param>
- public DataGridLength(double value)
- : this(value, DataGridLengthUnitType.Pixel)
- {
- }
- /// <summary>
- /// Initializes to a specified value and unit.
- /// </summary>
- /// <param name="value">The value to hold.</param>
- /// <param name="type">The unit of <c>value</c>.</param>
- /// <remarks>
- /// <c>value</c> is ignored unless <c>type</c> is
- /// <c>DataGridLengthUnitType.Pixel</c> or
- /// <c>DataGridLengthUnitType.Star</c>
- /// </remarks>
- /// <exception cref="ArgumentException">
- /// If <c>value</c> parameter is <c>double.NaN</c>
- /// or <c>value</c> parameter is <c>double.NegativeInfinity</c>
- /// or <c>value</c> parameter is <c>double.PositiveInfinity</c>.
- /// </exception>
- public DataGridLength(double value, DataGridLengthUnitType type)
- : this(value, type, (type == DataGridLengthUnitType.Pixel ? value : Double.NaN), (type == DataGridLengthUnitType.Pixel ? value : Double.NaN))
- {
- }
- /// <summary>
- /// Initializes to a specified value and unit.
- /// </summary>
- /// <param name="value">The value to hold.</param>
- /// <param name="type">The unit of <c>value</c>.</param>
- /// <param name="desiredValue"></param>
- /// <param name="displayValue"></param>
- /// <remarks>
- /// <c>value</c> is ignored unless <c>type</c> is
- /// <c>DataGridLengthUnitType.Pixel</c> or
- /// <c>DataGridLengthUnitType.Star</c>
- /// </remarks>
- /// <exception cref="ArgumentException">
- /// If <c>value</c> parameter is <c>double.NaN</c>
- /// or <c>value</c> parameter is <c>double.NegativeInfinity</c>
- /// or <c>value</c> parameter is <c>double.PositiveInfinity</c>.
- /// </exception>
- public DataGridLength(double value, DataGridLengthUnitType type, double desiredValue, double displayValue)
- {
- if (double.IsNaN(value))
- {
- throw DataGridError.DataGrid.ValueCannotBeSetToNAN("value");
- }
- if (double.IsInfinity(value))
- {
- throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("value");
- }
- if (double.IsInfinity(desiredValue))
- {
- throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("desiredValue");
- }
- if (double.IsInfinity(displayValue))
- {
- throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("displayValue");
- }
- if (value < 0)
- {
- throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "value", 0);
- }
- if (desiredValue < 0)
- {
- throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("desiredValue", "desiredValue", 0);
- }
- if (displayValue < 0)
- {
- throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("displayValue", "displayValue", 0);
- }
- if (type != DataGridLengthUnitType.Auto &&
- type != DataGridLengthUnitType.SizeToCells &&
- type != DataGridLengthUnitType.SizeToHeader &&
- type != DataGridLengthUnitType.Star &&
- type != DataGridLengthUnitType.Pixel)
- {
- throw DataGridError.DataGridLength.InvalidUnitType("type");
- }
- _desiredValue = desiredValue;
- _displayValue = displayValue;
- _unitValue = (type == DataGridLengthUnitType.Auto) ? DATAGRIDLENGTH_DefaultValue : value;
- _unitType = type;
- }
- /// <summary>
- /// Gets a <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the standard automatic sizing mode.
- /// </summary>
- /// <returns>
- /// A <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the standard automatic sizing mode.
- /// </returns>
- public static DataGridLength Auto
- {
- get
- {
- return _auto;
- }
- }
- /// <summary>
- /// Returns the desired value of this instance.
- /// </summary>
- public double DesiredValue
- {
- get
- {
- return _desiredValue;
- }
- }
- /// <summary>
- /// Returns the display value of this instance.
- /// </summary>
- public double DisplayValue
- {
- get
- {
- return _displayValue;
- }
- }
- /// <summary>
- /// Returns <c>true</c> if this DataGridLength instance holds
- /// an absolute (pixel) value.
- /// </summary>
- public bool IsAbsolute
- {
- get
- {
- return _unitType == DataGridLengthUnitType.Pixel;
- }
- }
- /// <summary>
- /// Returns <c>true</c> if this DataGridLength instance is
- /// automatic (not specified).
- /// </summary>
- public bool IsAuto
- {
- get
- {
- return _unitType == DataGridLengthUnitType.Auto;
- }
- }
- /// <summary>
- /// Returns <c>true</c> if this instance is to size to the cells of a column or row.
- /// </summary>
- public bool IsSizeToCells
- {
- get
- {
- return _unitType == DataGridLengthUnitType.SizeToCells;
- }
- }
- /// <summary>
- /// Returns <c>true</c> if this instance is to size to the header of a column or row.
- /// </summary>
- public bool IsSizeToHeader
- {
- get
- {
- return _unitType == DataGridLengthUnitType.SizeToHeader;
- }
- }
- /// <summary>
- /// Returns <c>true</c> if this DataGridLength instance holds a weighted proportion
- /// of available space.
- /// </summary>
- public bool IsStar
- {
- get
- {
- return _unitType == DataGridLengthUnitType.Star;
- }
- }
- /// <summary>
- /// Gets a <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the cell-based automatic sizing mode.
- /// </summary>
- /// <returns>
- /// A <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the cell-based automatic sizing mode.
- /// </returns>
- public static DataGridLength SizeToCells
- {
- get
- {
- return _sizeToCells;
- }
- }
- /// <summary>
- /// Gets a <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the header-based automatic sizing mode.
- /// </summary>
- /// <returns>
- /// A <see cref="T:Avalonia.Controls.DataGridLength" /> structure that represents the header-based automatic sizing mode.
- /// </returns>
- public static DataGridLength SizeToHeader
- {
- get
- {
- return _sizeToHeader;
- }
- }
- /// <summary>
- /// Gets the <see cref="T:Avalonia.Controls.DataGridLengthUnitType" /> that represents the current sizing mode.
- /// </summary>
- public DataGridLengthUnitType UnitType
- {
- get
- {
- return _unitType;
- }
- }
- /// <summary>
- /// Gets the absolute value of the <see cref="T:Avalonia.Controls.DataGridLength" /> in pixels.
- /// </summary>
- /// <returns>
- /// The absolute value of the <see cref="T:Avalonia.Controls.DataGridLength" /> in pixels.
- /// </returns>
- public double Value
- {
- get
- {
- return _unitValue;
- }
- }
- /// <summary>
- /// Overloaded operator, compares 2 DataGridLength's.
- /// </summary>
- /// <param name="gl1">first DataGridLength to compare.</param>
- /// <param name="gl2">second DataGridLength to compare.</param>
- /// <returns>true if specified DataGridLength have same value,
- /// unit type, desired value, and display value.</returns>
- public static bool operator ==(DataGridLength gl1, DataGridLength gl2)
- {
- return (gl1.UnitType == gl2.UnitType
- && gl1.Value == gl2.Value
- && gl1.DesiredValue == gl2.DesiredValue
- && gl1.DisplayValue == gl2.DisplayValue);
- }
- /// <summary>
- /// Overloaded operator, compares 2 DataGridLength's.
- /// </summary>
- /// <param name="gl1">first DataGridLength to compare.</param>
- /// <param name="gl2">second DataGridLength to compare.</param>
- /// <returns>true if specified DataGridLength have either different value,
- /// unit type, desired value, or display value.</returns>
- public static bool operator !=(DataGridLength gl1, DataGridLength gl2)
- {
- return (gl1.UnitType != gl2.UnitType
- || gl1.Value != gl2.Value
- || gl1.DesiredValue != gl2.DesiredValue
- || gl1.DisplayValue != gl2.DisplayValue);
- }
- /// <summary>
- /// Compares this instance of DataGridLength with another instance.
- /// </summary>
- /// <param name="other">DataGridLength length instance to compare.</param>
- /// <returns><c>true</c> if this DataGridLength instance has the same value
- /// and unit type as gridLength.</returns>
- public bool Equals(DataGridLength other)
- {
- return (this == other);
- }
- /// <summary>
- /// Compares this instance of DataGridLength with another object.
- /// </summary>
- /// <param name="obj">Reference to an object for comparison.</param>
- /// <returns><c>true</c> if this DataGridLength instance has the same value
- /// and unit type as oCompare.</returns>
- public override bool Equals(object obj)
- {
- DataGridLength? dataGridLength = obj as DataGridLength?;
- if (dataGridLength.HasValue)
- {
- return (this == dataGridLength);
- }
- return false;
- }
- /// <summary>
- /// Returns a unique hash code for this DataGridLength
- /// </summary>
- /// <returns>hash code</returns>
- public override int GetHashCode()
- {
- return ((int)_unitValue + (int)_unitType) + (int)_desiredValue + (int)_displayValue;
- }
- }
- /// <summary>
- /// DataGridLengthConverter - Converter class for converting instances of other types to and from DataGridLength instances.
- /// </summary>
- public class DataGridLengthConverter : TypeConverter
- {
- private static string _starSuffix = "*";
- private static string[] _valueInvariantUnitStrings = { "auto", "sizetocells", "sizetoheader" };
- private static DataGridLength[] _valueInvariantDataGridLengths = { DataGridLength.Auto, DataGridLength.SizeToCells, DataGridLength.SizeToHeader };
- /// <summary>
- /// Checks whether or not this class can convert from a given type.
- /// </summary>
- /// <param name="context">
- /// An ITypeDescriptorContext that provides a format context.
- /// </param>
- /// <param name="sourceType">The Type being queried for support.</param>
- /// <returns>
- /// <c>true</c> if this converter can convert from the provided type,
- /// <c>false</c> otherwise.
- /// </returns>
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- // We can only handle strings, integral and floating types
- TypeCode tc = Type.GetTypeCode(sourceType);
- switch (tc)
- {
- case TypeCode.String:
- case TypeCode.Decimal:
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.UInt64:
- return true;
- default:
- return false;
- }
- }
- /// <summary>
- /// Checks whether or not this class can convert to a given type.
- /// </summary>
- /// <param name="context">
- /// An ITypeDescriptorContext that provides a format context.
- /// </param>
- /// <param name="destinationType">The Type being queried for support.</param>
- /// <returns>
- /// <c>true</c> if this converter can convert to the provided type,
- /// <c>false</c> otherwise.
- /// </returns>
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- return destinationType == typeof(string);
- }
- /// <summary>
- /// Attempts to convert to a DataGridLength from the given object.
- /// </summary>
- /// <param name="context">
- /// An ITypeDescriptorContext that provides a format context.
- /// </param>
- /// <param name="culture">
- /// The CultureInfo to use for the conversion.
- /// </param>
- /// <param name="value">The object to convert to a GridLength.</param>
- /// <returns>
- /// The GridLength instance which was constructed.
- /// </returns>
- /// <exception cref="NotSupportedException">
- /// A NotSupportedException is thrown if the example object is null.
- /// </exception>
- public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
- {
- // GridLengthConverter in WPF throws a NotSupportedException on a null value as well.
- if (value == null)
- {
- throw DataGridError.DataGridLengthConverter.CannotConvertFrom("(null)");
- }
- if (value is string stringValue)
- {
- stringValue = stringValue.Trim();
- if (stringValue.EndsWith(_starSuffix, StringComparison.Ordinal))
- {
- string stringValueWithoutSuffix = stringValue.Substring(0, stringValue.Length - _starSuffix.Length);
- double starWeight;
- if (string.IsNullOrEmpty(stringValueWithoutSuffix))
- {
- starWeight = 1;
- }
- else
- {
- starWeight = Convert.ToDouble(stringValueWithoutSuffix, culture ?? CultureInfo.CurrentCulture);
- }
- return new DataGridLength(starWeight, DataGridLengthUnitType.Star);
- }
- for (int index = 0; index < _valueInvariantUnitStrings.Length; index++)
- {
- if (stringValue.Equals(_valueInvariantUnitStrings[index], StringComparison.OrdinalIgnoreCase))
- {
- return _valueInvariantDataGridLengths[index];
- }
- }
- }
- // Conversion from numeric type, WPF lets Convert exceptions bubble out here as well
- double doubleValue = Convert.ToDouble(value, culture ?? CultureInfo.CurrentCulture);
- if (double.IsNaN(doubleValue))
- {
- // WPF returns Auto in this case as well
- return DataGridLength.Auto;
- }
- else
- {
- return new DataGridLength(doubleValue);
- }
- }
- /// <summary>
- /// Attempts to convert a DataGridLength instance to the given type.
- /// </summary>
- /// <param name="context">
- /// An ITypeDescriptorContext that provides a format context.
- /// </param>
- /// <param name="culture">
- /// The CultureInfo to use for the conversion.
- /// </param>
- /// <param name="value">The DataGridLength to convert.</param>
- /// <param name="destinationType">The type to which to convert the DataGridLength instance.</param>
- /// <returns>
- /// The object which was constructed.
- /// </returns>
- /// <exception cref="ArgumentNullException">
- /// An ArgumentNullException is thrown if the example object is null.
- /// </exception>
- /// <exception cref="NotSupportedException">
- /// A NotSupportedException is thrown if the object is not null and is not a DataGridLength,
- /// or if the destinationType isn't one of the valid destination types.
- /// </exception>
- ///<SecurityNote>
- /// Critical: calls InstanceDescriptor ctor which LinkDemands
- /// PublicOK: can only make an InstanceDescriptor for DataGridLength, not an arbitrary class
- ///</SecurityNote>
- public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
- {
- if (destinationType == null)
- {
- throw new ArgumentNullException("destinationType");
- }
- if (destinationType != typeof(string))
- {
- throw DataGridError.DataGridLengthConverter.CannotConvertTo(destinationType.ToString());
- }
- DataGridLength? dataGridLength = value as DataGridLength?;
- if (!dataGridLength.HasValue)
- {
- throw DataGridError.DataGridLengthConverter.InvalidDataGridLength("value");
- }
- else
- {
- // Convert dataGridLength to a string
- switch (dataGridLength.Value.UnitType)
- {
- // for Auto print out "Auto". value is always "1.0"
- case DataGridLengthUnitType.Auto:
- return "Auto";
- case DataGridLengthUnitType.SizeToHeader:
- return "SizeToHeader";
- case DataGridLengthUnitType.SizeToCells:
- return "SizeToCells";
- // Star has one special case when value is "1.0".
- // in this case drop value part and print only "Star"
- case DataGridLengthUnitType.Star:
- return (
- DoubleUtil.AreClose(1.0, dataGridLength.Value.Value)
- ? _starSuffix
- : Convert.ToString(dataGridLength.Value.Value, culture ?? CultureInfo.CurrentCulture) + DataGridLengthConverter._starSuffix);
- default:
- return (Convert.ToString(dataGridLength.Value.Value, culture ?? CultureInfo.CurrentCulture));
- }
- }
- }
- }
- }
|