From 5a8a9e7ce2006ea62c28fa466eee7ff4152abc1c Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 5 Jun 2019 22:13:46 +0800 Subject: [PATCH 01/11] Cleaning up --- src/Avalonia.Controls/ColumnDefinitions.cs | 4 +- src/Avalonia.Controls/DefinitionBase.cs | 273 ++---- src/Avalonia.Controls/DefinitionList.cs | 7 +- src/Avalonia.Controls/Grid.cs | 943 +++------------------ src/Avalonia.Controls/RowDefinitions.cs | 4 +- 5 files changed, 202 insertions(+), 1029 deletions(-) diff --git a/src/Avalonia.Controls/ColumnDefinitions.cs b/src/Avalonia.Controls/ColumnDefinitions.cs index 4f5bbf3bc3..d4fc2ee0a1 100644 --- a/src/Avalonia.Controls/ColumnDefinitions.cs +++ b/src/Avalonia.Controls/ColumnDefinitions.cs @@ -16,10 +16,8 @@ namespace Avalonia.Controls /// /// Initializes a new instance of the class. /// - public ColumnDefinitions() + public ColumnDefinitions() : base () { - ResetBehavior = ResetBehavior.Remove; - CollectionChanged += OnCollectionChanged; } /// diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index 8899c38bf9..d04578b371 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -20,49 +20,15 @@ namespace Avalonia.Controls /// public abstract class DefinitionBase : AvaloniaObject { - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - - #region Constructors - - /* internal DefinitionBase(bool isColumnDefinition) - { - _isColumnDefinition = isColumnDefinition; - _parentIndex = -1; - }*/ - - #endregion Constructors - - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - - #region Public Properties - /// /// SharedSizeGroup property. /// public string SharedSizeGroup { - get { return (string) GetValue(SharedSizeGroupProperty); } + get { return (string)GetValue(SharedSizeGroupProperty); } set { SetValue(SharedSizeGroupProperty, value); } } - #endregion Public Properties - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - - #region Internal Methods - /// /// Callback to notify about entering model tree. /// @@ -91,7 +57,7 @@ namespace Avalonia.Controls if (e.Property.PropertyType == typeof(GridLength) || e.Property.PropertyType == typeof(double)) OnUserSizePropertyChanged(e); - + base.OnPropertyChanged(e); } @@ -139,9 +105,6 @@ namespace Avalonia.Controls _minSize = minSize; } - /// - /// - /// /// /// This method needs to be internal to be accessable from derived classes. /// @@ -166,92 +129,29 @@ namespace Avalonia.Controls } } } - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserSizePropertyValueValid(object value) - { - return (((GridLength)value).Value >= 0); - } - /// - /// - /// /// /// This method needs to be internal to be accessable from derived classes. /// internal static void OnUserMinSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - DefinitionBase definition = (DefinitionBase) d; - - if (definition.InParentLogicalTree) - { - Grid parentGrid = (Grid) definition.Parent; - parentGrid.InvalidateMeasure(); - } - } - - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserMinSizePropertyValueValid(object value) - { - double v = (double)value; - return (!double.IsNaN(v) && v >= 0.0d && !Double.IsPositiveInfinity(v)); - } - - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static void OnUserMaxSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) - { - DefinitionBase definition = (DefinitionBase) d; + DefinitionBase definition = (DefinitionBase)d; if (definition.InParentLogicalTree) { - Grid parentGrid = (Grid) definition.Parent; + Grid parentGrid = (Grid)definition.Parent; parentGrid.InvalidateMeasure(); } } - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserMaxSizePropertyValueValid(object value) - { - double v = (double)value; - return (!double.IsNaN(v) && v >= 0.0d); - } - - /// - /// - /// /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty /// is a collection of SharedSizeState objects for the scope. - /// Also PrivateSharedSizeScopeProperty is FrameworkPropertyMetadataOptions.Inherits property. So that all children - /// elements belonging to a certain scope can easily access SharedSizeState collection. As well - /// as been norified about enter / exit a scope. /// internal static void OnIsSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - // is it possible to optimize here something like this: - // if ((bool)d.GetValue(Grid.IsSharedSizeScopeProperty) == (d.GetLocalValue(PrivateSharedSizeScopeProperty) != null) - // { /* do nothing */ } - if ((bool) e.NewValue) + if ((bool)e.NewValue) { SharedSizeScope sharedStatesCollection = new SharedSizeScope(); d.SetValue(PrivateSharedSizeScopeProperty, sharedStatesCollection); @@ -262,16 +162,6 @@ namespace Avalonia.Controls } } - #endregion Internal Methods - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - - #region Internal Properties - /// /// Returns true if this definition is a part of shared group. /// @@ -349,8 +239,8 @@ namespace Avalonia.Controls get { double preferredSize = MinSize; - if ( _sizeType != Grid.LayoutTimeSizeType.Auto - && preferredSize < _measureSize ) + if (_sizeType != Grid.LayoutTimeSizeType.Auto + && preferredSize < _measureSize) { preferredSize = _measureSize; } @@ -375,9 +265,9 @@ namespace Avalonia.Controls get { double minSize = _minSize; - if ( UseSharedMinimum - && _sharedState != null - && minSize < _sharedState.MinSize ) + if (UseSharedMinimum + && _sharedState != null + && minSize < _sharedState.MinSize) { minSize = _sharedState.MinSize; } @@ -393,9 +283,9 @@ namespace Avalonia.Controls get { double minSize = _minSize; - if ( _sharedState != null - && (UseSharedMinimum || !LayoutWasUpdated) - && minSize < _sharedState.MinSize ) + if (_sharedState != null + && (UseSharedMinimum || !LayoutWasUpdated) + && minSize < _sharedState.MinSize) { minSize = _sharedState.MinSize; } @@ -426,7 +316,7 @@ namespace Avalonia.Controls /// Internal helper to access up-to-date UserMaxSize property value. /// internal abstract double UserMaxSizeValueCache { get; } - + /// /// Protected. Returns true if this DefinitionBase instance is in parent's logical tree. /// @@ -437,16 +327,6 @@ namespace Avalonia.Controls internal Grid Parent { get; set; } - #endregion Internal Properties - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - #region Private Methods - /// /// SetFlags is used to set or unset one or multiple /// flags on the object. @@ -465,16 +345,13 @@ namespace Avalonia.Controls return ((_flags & flags) == flags); } - /// - /// - /// private static void OnSharedSizeGroupPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - DefinitionBase definition = (DefinitionBase) d; - + DefinitionBase definition = (DefinitionBase)d; + if (definition.InParentLogicalTree) { - string sharedSizeGroupId = (string) e.NewValue; + string sharedSizeGroupId = (string)e.NewValue; if (definition._sharedState != null) { @@ -483,7 +360,7 @@ namespace Avalonia.Controls definition._sharedState.RemoveMember(definition); definition._sharedState = null; } - + if ((definition._sharedState == null) && (sharedSizeGroupId != null)) { SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope; @@ -498,9 +375,6 @@ namespace Avalonia.Controls } } - /// - /// - /// /// /// Verifies that Shared Size Group Property string /// a) not empty. @@ -520,10 +394,10 @@ namespace Avalonia.Controls { bool isDigit = Char.IsDigit(id[i]); - if ( (i == 0 && isDigit) - || !( isDigit - || Char.IsLetter(id[i]) - || '_' == id[i] ) ) + if ((i == 0 && isDigit) + || !(isDigit + || Char.IsLetter(id[i]) + || '_' == id[i])) { break; } @@ -535,12 +409,9 @@ namespace Avalonia.Controls } } - throw new ArgumentException("Invalid SharedSizeGroup string."); + throw new ArgumentException("Invalid SharedSizeGroup string."); } - /// - /// - /// /// /// OnPrivateSharedSizeScopePropertyChanged is called when new scope enters or /// existing scope just left. In both cases if the DefinitionBase object is already registered @@ -552,7 +423,7 @@ namespace Avalonia.Controls if (definition.InParentLogicalTree) { - SharedSizeScope privateSharedSizeScope = (SharedSizeScope) e.NewValue; + SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; if (definition._sharedState != null) { @@ -576,22 +447,12 @@ namespace Avalonia.Controls } } - #endregion Private Methods - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - - #region Private Properties - /// /// Private getter of shared state collection dynamic property. /// private SharedSizeScope PrivateSharedSizeScope { - get { return (SharedSizeScope) GetValue(PrivateSharedSizeScopeProperty); } + get { return (SharedSizeScope)GetValue(PrivateSharedSizeScopeProperty); } } /// @@ -612,16 +473,6 @@ namespace Avalonia.Controls set { SetFlags(value, Flags.LayoutWasUpdated); } } - #endregion Private Properties - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - - #region Private Fields - private readonly bool _isColumnDefinition; // when "true", this is a ColumnDefinition; when "false" this is a RowDefinition (faster than a type check) private Flags _flags; // flags reflecting various aspects of internal state internal int _parentIndex = -1; // this instance's index in parent's children collection @@ -633,19 +484,6 @@ namespace Avalonia.Controls private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case) private SharedSizeState _sharedState; // reference to shared state object this instance is registered with - - internal const bool ThisIsColumnDefinition = true; - internal const bool ThisIsRowDefinition = false; - - #endregion Private Fields - - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - - #region Private Structures Classes [System.Flags] private enum Flags : byte @@ -653,8 +491,8 @@ namespace Avalonia.Controls // // bool flags // - UseSharedMinimum = 0x00000020, // when "1", definition will take into account shared state's minimum - LayoutWasUpdated = 0x00000040, // set to "1" every time the parent grid is measured + UseSharedMinimum = 0x00000020, // when "1", definition will take into account shared state's minimum + LayoutWasUpdated = 0x00000040, // set to "1" every time the parent grid is measured } /// @@ -799,8 +637,8 @@ namespace Avalonia.Controls for (int i = 0, count = _registry.Count; i < count; ++i) { - Debug.Assert( _userSize.GridUnitType == GridUnitType.Auto - || _userSize.GridUnitType == GridUnitType.Pixel ); + Debug.Assert(_userSize.GridUnitType == GridUnitType.Auto + || _userSize.GridUnitType == GridUnitType.Pixel); GridLength currentGridLength = _registry[i].UserSizeValueCache; if (currentGridLength.GridUnitType == GridUnitType.Pixel) @@ -845,7 +683,7 @@ namespace Avalonia.Controls { DefinitionBase definitionBase = _registry[i]; - if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) + if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) { // if definition's min size is different, then need to re-measure if (!MathUtilities.AreClose(sharedMinSize, definitionBase.MinSize)) @@ -857,7 +695,7 @@ namespace Avalonia.Controls 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 @@ -879,27 +717,34 @@ namespace Avalonia.Controls _broadcastInvalidation = true; } - - private readonly SharedSizeScope _sharedSizeScope; // the scope this state belongs to - private readonly string _sharedSizeGroupId; // Id of the shared size group this object is servicing - private readonly List _registry; // registry of participating definitions - private readonly EventHandler _layoutUpdated; // instance event handler for layout updated event - private Control _layoutUpdatedHost; // Control for which layout updated event handler is registered - private bool _broadcastInvalidation; // "true" when broadcasting of invalidation is needed - private bool _userSizeValid; // "true" when _userSize is up to date - private GridLength _userSize; // shared state - private double _minSize; // shared state - } - #endregion Private Structures Classes + // the scope this state belongs to + private readonly SharedSizeScope _sharedSizeScope; + + // Id of the shared size group this object is servicing + private readonly string _sharedSizeGroupId; + + // Registry of participating definitions + private readonly List _registry; + + // Instance event handler for layout updated event + private readonly EventHandler _layoutUpdated; - //------------------------------------------------------ - // - // Properties - // - //------------------------------------------------------ + // Control for which layout updated event handler is registered + private Control _layoutUpdatedHost; - #region Properties + // "true" when broadcasting of invalidation is needed + private bool _broadcastInvalidation; + + // "true" when _userSize is up to date + private bool _userSizeValid; + + // shared state + private GridLength _userSize; + + // shared state + private double _minSize; + } /// /// Private shared size scope property holds a collection of shared state objects for the a given shared size scope. @@ -931,7 +776,7 @@ namespace Avalonia.Controls public static readonly AttachedProperty SharedSizeGroupProperty = AvaloniaProperty.RegisterAttached( "SharedSizeGroup", - validate:SharedSizeGroupPropertyValueValid); + validate: SharedSizeGroupPropertyValueValid); /// /// Static ctor. Used for static registration of properties. @@ -941,7 +786,5 @@ namespace Avalonia.Controls SharedSizeGroupProperty.Changed.AddClassHandler(OnSharedSizeGroupPropertyChanged); PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged); } - - #endregion Properties } -} +} \ No newline at end of file diff --git a/src/Avalonia.Controls/DefinitionList.cs b/src/Avalonia.Controls/DefinitionList.cs index b36ca9ce8a..97d92bdcb7 100644 --- a/src/Avalonia.Controls/DefinitionList.cs +++ b/src/Avalonia.Controls/DefinitionList.cs @@ -10,6 +10,12 @@ namespace Avalonia.Controls { public abstract class DefinitionList : AvaloniaList where T : DefinitionBase { + public DefinitionList() + { + ResetBehavior = ResetBehavior.Remove; + CollectionChanged += OnCollectionChanged; + } + internal bool IsDirty = true; private Grid _parent; @@ -19,7 +25,6 @@ namespace Avalonia.Controls set => SetParent(value); } - private void SetParent(Grid value) { _parent = value; diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index fc61c409f0..5a44b93941 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -22,12 +22,6 @@ namespace Avalonia.Controls /// public class Grid : Panel { - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - static Grid() { IsSharedSizeScopeProperty.Changed.AddClassHandler(DefinitionBase.OnIsSharedSizeScopePropertyChanged); @@ -47,42 +41,6 @@ namespace Avalonia.Controls { } - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - - - /// - /// - /// - /* protected internal override IEnumerator LogicalChildren - { - get - { - // empty panel or a panel being used as the items - // host has *no* logical children; give empty enumerator - bool noChildren = (base.VisualChildrenCount == 0) || IsItemsHost; - - if (noChildren) - { - ExtendedData extData = ExtData; - - if ( extData == null - || ( (extData.ColumnDefinitions == null || extData.ColumnDefinitions.Count == 0) - && (extData.RowDefinitions == null || extData.RowDefinitions.Count == 0) ) - ) - { - // grid is empty - return EmptyEnumerator.Instance; - } - } - - return (new GridChildrenCollectionEnumeratorSimple(this, !noChildren)); - } - } */ - /// /// Helper for setting Column property on a Control. /// @@ -193,12 +151,6 @@ namespace Avalonia.Controls return element.GetValue(IsSharedSizeScopeProperty); } - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - /// /// ShowGridLines property. /// @@ -248,52 +200,6 @@ namespace Avalonia.Controls } } - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - - /* /// - /// Derived class must implement to support Visual children. The method must return - /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. - /// - /// By default a Visual does not have any children. - /// - /// Remark: - /// During this virtual call it is not valid to modify the Visual tree. - /// - protected override Visual GetVisualChild(int index) - { - // because "base.Count + 1" for GridLinesRenderer - // argument checking done at the base class - if(index == base.VisualChildrenCount) - { - if (_gridLinesRenderer == null) - { - throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); - } - return _gridLinesRenderer; - } - else return base.GetVisualChild(index); - } - - /// - /// Derived classes override this property to enable the Visual code to enumerate - /// the Visual children. Derived classes need to return the number of children - /// from this method. - /// - /// By default a Visual does not have any children. - /// - /// Remark: During this virtual method the Visual tree must not be modified. - /// - protected override int VisualChildrenCount - { - //since GridLinesRenderer has not been added as a child, so we do not subtract - get { return base.VisualChildrenCount + (_gridLinesRenderer != null ? 1 : 0); } - }*/ - - /// /// Content measurement. /// @@ -306,8 +212,6 @@ namespace Avalonia.Controls try { - - ListenToNotifications = true; MeasureOverrideInProgress = true; @@ -550,7 +454,7 @@ namespace Avalonia.Controls // also use a count heuristic to break a loop in case of one. bool hasDesiredSizeUChanged = false; - int cnt=0; + int cnt = 0; // Cache Group2MinWidths & Group3MinHeights double[] group2MinSizes = CacheMinSizes(extData.CellGroup2, false); @@ -582,17 +486,14 @@ namespace Avalonia.Controls MeasureCellsGroup(extData.CellGroup4, constraint, false, false); - gridDesiredSize = new Size( CalculateDesiredSize(DefinitionsU), CalculateDesiredSize(DefinitionsV)); - } } finally { MeasureOverrideInProgress = false; - } return (gridDesiredSize); @@ -606,8 +507,6 @@ namespace Avalonia.Controls { try { - - ArrangeOverrideInProgress = true; if (_data == null) @@ -627,13 +526,9 @@ namespace Avalonia.Controls { Debug.Assert(DefinitionsU.Count > 0 && DefinitionsV.Count > 0); - - SetFinalSize(DefinitionsU, arrangeSize.Width, true); SetFinalSize(DefinitionsV, arrangeSize.Height, false); - - var children = this.Children; for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell) @@ -653,11 +548,11 @@ namespace Avalonia.Controls columnIndex == 0 ? 0.0 : DefinitionsU[columnIndex].FinalOffset, rowIndex == 0 ? 0.0 : DefinitionsV[rowIndex].FinalOffset, GetFinalSizeForRange(DefinitionsU, columnIndex, columnSpan), - GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan) ); + GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan)); + - cell.Arrange(cellRect); - + } // update render bound on grid lines renderer visual @@ -669,31 +564,12 @@ namespace Avalonia.Controls { SetValid(); ArrangeOverrideInProgress = false; - } return (arrangeSize); } /// - /// - /// - /*protected internal override void OnVisualChildrenChanged( - AvaloniaObject visualAdded, - AvaloniaObject visualRemoved) - { - CellsStructureDirty = true; - - base.OnVisualChildrenChanged(visualAdded, visualRemoved); - }*/ - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - - /// - /// Invalidates grid caches and makes the grid dirty for measure. + /// Invalidates grid caches and makes the grid dirty for measure. /// internal void Invalidate() { @@ -702,10 +578,10 @@ namespace Avalonia.Controls } /// - /// Returns final width for a column. + /// Returns final width for a column. /// /// - /// Used from public ColumnDefinition ActualWidth. Calculates final width using offset data. + /// Used from public ColumnDefinition ActualWidth. Calculates final width using offset data. /// internal double GetFinalColumnDefinitionWidth(int columnIndex) { @@ -724,10 +600,10 @@ namespace Avalonia.Controls } /// - /// Returns final height for a row. + /// Returns final height for a row. /// /// - /// Used from public RowDefinition ActualHeight. Calculates final height using offset data. + /// Used from public RowDefinition ActualHeight. Calculates final height using offset data. /// internal double GetFinalRowDefinitionHeight(int rowIndex) { @@ -745,12 +621,6 @@ namespace Avalonia.Controls return (value); } - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - /// /// Convenience accessor to MeasureOverrideInProgress bit flag. /// @@ -781,32 +651,22 @@ namespace Avalonia.Controls /// /// Convenience accessor to ValidDefinitionsVStructure bit flag. /// - internal bool RowDefinitionsDirty + internal bool RowDefinitionsDirty { get => RowDefinitions?.IsDirty ?? false; set => RowDefinitions.IsDirty = value; } - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - /// /// Lays out cells according to rows and columns, and creates lookup grids. /// private void ValidateCells() { - - if (CellsStructureDirty) { ValidateCellsCore(); CellsStructureDirty = false; } - - } /// @@ -837,11 +697,8 @@ namespace Avalonia.Controls CellCache cell = new CellCache(); - // - // read and cache child positioning properties - // - // read indices from the corresponding properties + // Read indices from the corresponding properties: // clamp to value < number_of_columns // column >= 0 is guaranteed by property value validation callback cell.ColumnIndex = Math.Min(GetColumn((Control)child), DefinitionsU.Count - 1); @@ -849,7 +706,7 @@ namespace Avalonia.Controls // row >= 0 is guaranteed by property value validation callback cell.RowIndex = Math.Min(GetRow((Control)child), DefinitionsV.Count - 1); - // read span properties + // Read span properties: // clamp to not exceed beyond right side of the grid // column_span > 0 is guaranteed by property value validation callback cell.ColumnSpan = Math.Min(GetColumnSpan((Control)child), DefinitionsU.Count - cell.ColumnIndex); @@ -861,9 +718,7 @@ namespace Avalonia.Controls Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Count); Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Count); - // - // calculate and cache length types for the child - // + // Calculate and cache length types for the child. cell.SizeTypeU = GetLengthTypeForRange(DefinitionsU, cell.ColumnIndex, cell.ColumnSpan); cell.SizeTypeV = GetLengthTypeForRange(DefinitionsV, cell.RowIndex, cell.RowSpan); @@ -871,9 +726,7 @@ namespace Avalonia.Controls hasStarCellsU |= cell.IsStarU; hasStarCellsV |= cell.IsStarV; - // - // distribute cells into four groups. - // + // Distribute cells into four groups. if (!cell.IsStarV) { @@ -887,15 +740,15 @@ namespace Avalonia.Controls cell.Next = extData.CellGroup3; extData.CellGroup3 = i; - // remember if this cell belongs to auto row + // Remember if this cell belongs to auto row hasGroup3CellsInAutoRows |= cell.IsAutoV; } } else { - if ( cell.IsAutoU - // note below: if spans through Star column it is NOT Auto - && !cell.IsStarU ) + if (cell.IsAutoU + // Note below: if spans through Star column it is NOT Auto + && !cell.IsStarU) { cell.Next = extData.CellGroup2; extData.CellGroup2 = i; @@ -986,7 +839,7 @@ namespace Avalonia.Controls extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() { Parent = this } }; } else - { + { extData.DefinitionsV = extData.RowDefinitions; } } @@ -1053,7 +906,7 @@ namespace Avalonia.Controls { double[] minSizes = isRows ? new double[DefinitionsV.Count] : new double[DefinitionsU.Count]; - for (int j=0; j (double)o ) + if (o == null + || value > (double)o) { store[key] = value; } @@ -1235,13 +1088,13 @@ namespace Avalonia.Controls int cell, bool forceInfinityV) { - + double cellMeasureWidth; double cellMeasureHeight; - if ( PrivateCells[cell].IsAutoU - && !PrivateCells[cell].IsStarU ) + if (PrivateCells[cell].IsAutoU + && !PrivateCells[cell].IsStarU) { // if cell belongs to at least one Auto column and not a single Star column // then it should be calculated "to content", thus it is possible to "shortcut" @@ -1261,8 +1114,8 @@ namespace Avalonia.Controls { cellMeasureHeight = double.PositiveInfinity; } - else if ( PrivateCells[cell].IsAutoV - && !PrivateCells[cell].IsStarV ) + else if (PrivateCells[cell].IsAutoV + && !PrivateCells[cell].IsStarV) { // if cell belongs to at least one Auto row and not a single Star row // then it should be calculated "to content", thus it is possible to "shortcut" @@ -1277,19 +1130,18 @@ namespace Avalonia.Controls PrivateCells[cell].RowSpan); } - + var child = this.Children[cell]; if (child != null) { Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight); child.Measure(childConstraint); } - - - } + } + /// /// Calculates one dimensional measure size for given definitions' range. /// @@ -1393,12 +1245,12 @@ namespace Avalonia.Controls // sanity check: no matter what, but min size must always be the smaller; // max size must be the biggest; and preferred should be in between - Debug.Assert( minSize <= preferredSize - && preferredSize <= maxSize - && rangeMinSize <= rangePreferredSize - && rangePreferredSize <= rangeMaxSize ); + Debug.Assert(minSize <= preferredSize + && preferredSize <= maxSize + && rangeMinSize <= rangePreferredSize + && rangePreferredSize <= rangeMaxSize); - if (maxMaxSize < maxSize) maxMaxSize = maxSize; + if (maxMaxSize < maxSize) maxMaxSize = maxSize; if (definitions[i].UserSize.IsAuto) autoDefinitionsCount++; tempDefinitions[i - start] = definitions[i]; } @@ -1492,8 +1344,8 @@ namespace Avalonia.Controls // double equalSize = requestedSize / count; - if ( equalSize < maxMaxSize - && !_AreClose(equalSize, maxMaxSize) ) + if (equalSize < maxMaxSize + && !_AreClose(equalSize, maxMaxSize)) { // equi-size is less than maximum of maxSizes. // in this case distribute so that smaller definitions grow faster than @@ -1502,12 +1354,12 @@ namespace Avalonia.Controls double sizeToDistribute = requestedSize - rangeMaxSize; // sanity check: totalRemainingSize and sizeToDistribute must be real positive numbers - Debug.Assert( !double.IsInfinity(totalRemainingSize) - && !double.IsNaN(totalRemainingSize) - && totalRemainingSize > 0 - && !double.IsInfinity(sizeToDistribute) - && !double.IsNaN(sizeToDistribute) - && sizeToDistribute > 0 ); + Debug.Assert(!double.IsInfinity(totalRemainingSize) + && !double.IsNaN(totalRemainingSize) + && totalRemainingSize > 0 + && !double.IsInfinity(sizeToDistribute) + && !double.IsNaN(sizeToDistribute) + && sizeToDistribute > 0); for (int i = 0; i < count; ++i) { @@ -1543,105 +1395,10 @@ namespace Avalonia.Controls IReadOnlyList definitions, double availableSize) { - // if (FrameworkAppContextSwitches.GridStarDefinitionsCanExceedAvailableSpace) - // { - // ResolveStarLegacy(definitions, availableSize); - // } - // else - // { - ResolveStarMaxDiscrepancy(definitions, availableSize); - // } + ResolveStarMaxDiscrepancy(definitions, availableSize); } - // original implementation, used from 3.0 through 4.6.2 - private void ResolveStarLegacy( - IReadOnlyList definitions, - double availableSize) - { - DefinitionBase[] tempDefinitions = TempDefinitions; - int starDefinitionsCount = 0; - double takenSize = 0; - - for (int i = 0; i < definitions.Count; ++i) - { - switch (definitions[i].SizeType) - { - case (LayoutTimeSizeType.Auto): - takenSize += definitions[i].MinSize; - break; - case (LayoutTimeSizeType.Pixel): - takenSize += definitions[i].MeasureSize; - break; - case (LayoutTimeSizeType.Star): - { - tempDefinitions[starDefinitionsCount++] = definitions[i]; - - double starValue = definitions[i].UserSize.Value; - - if (_IsZero(starValue)) - { - definitions[i].MeasureSize = 0; - definitions[i].SizeCache = 0; - } - else - { - // clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values - // can be summed up without overflow - starValue = Math.Min(starValue, c_starClip); - - // Note: normalized star value is temporary cached into MeasureSize - definitions[i].MeasureSize = starValue; - double maxSize = Math.Max(definitions[i].MinSize, definitions[i].UserMaxSize); - maxSize = Math.Min(maxSize, c_starClip); - definitions[i].SizeCache = maxSize / starValue; - } - } - break; - } - } - - if (starDefinitionsCount > 0) - { - Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer); - - // the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow... - // partial sum value is stored in each definition's SizeCache member. - // this way the algorithm guarantees (starValue <= definition.SizeCache) and thus - // (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. - // this is an important change from previous implementation where the following was possible: - // ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... - double allStarWeights = 0; - int i = starDefinitionsCount - 1; - do - { - allStarWeights += tempDefinitions[i].MeasureSize; - tempDefinitions[i].SizeCache = allStarWeights; - } while (--i >= 0); - - i = 0; - do - { - double resolvedSize; - double starValue = tempDefinitions[i].MeasureSize; - - if (_IsZero(starValue)) - { - resolvedSize = tempDefinitions[i].MinSize; - } - else - { - double userSize = Math.Max(availableSize - takenSize, 0.0) * (starValue / tempDefinitions[i].SizeCache); - resolvedSize = Math.Min(userSize, tempDefinitions[i].UserMaxSize); - resolvedSize = Math.Max(tempDefinitions[i].MinSize, resolvedSize); - } - - tempDefinitions[i].MeasureSize = resolvedSize; - takenSize += resolvedSize; - } while (++i < starDefinitionsCount); - } - } - - // new implementation as of 4.7. Several improvements: + // New implementation as of 4.7. Several improvements: // 1. Allocate to *-defs hitting their min or max constraints, before allocating // to other *-defs. A def that hits its min uses more space than its // proportional share, reducing the space available to everyone else. @@ -1668,7 +1425,7 @@ namespace Avalonia.Controls // Phase 1. Determine the maximum *-weight and prepare to adjust *-weights double maxStar = 0.0; - for (int i=0; i definitions, - double finalSize, - bool columns) - { - int starDefinitionsCount = 0; // traverses form the first entry up - int nonStarIndex = definitions.Count; // traverses from the last entry down - double allPreferredArrangeSize = 0; - bool useLayoutRounding = this.UseLayoutRounding; - int[] definitionIndices = DefinitionIndices; - double[] roundingErrors = null; - - // If using layout rounding, check whether rounding needs to compensate for high DPI - double dpi = 1.0; - - if (useLayoutRounding) - { - // DpiScale dpiScale = GetDpi(); - // dpi = columns ? dpiScale.DpiScaleX : dpiScale.DpiScaleY; - dpi = (VisualRoot as Layout.ILayoutRoot)?.LayoutScaling ?? 1.0; - roundingErrors = RoundingErrors; - } - - for (int i = 0; i < definitions.Count; ++i) - { - // if definition is shared then is cannot be star - Debug.Assert(!definitions[i].IsShared || !definitions[i].UserSize.IsStar); - - if (definitions[i].UserSize.IsStar) - { - double starValue = definitions[i].UserSize.Value; - - if (_IsZero(starValue)) - { - // cach normilized star value temporary into MeasureSize - definitions[i].MeasureSize = 0; - definitions[i].SizeCache = 0; - } - else - { - // clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values - // can be summed up without overflow - starValue = Math.Min(starValue, c_starClip); - - // Note: normalized star value is temporary cached into MeasureSize - definitions[i].MeasureSize = starValue; - double maxSize = Math.Max(definitions[i].MinSizeForArrange, definitions[i].UserMaxSize); - maxSize = Math.Min(maxSize, c_starClip); - definitions[i].SizeCache = maxSize / starValue; - if (useLayoutRounding) - { - roundingErrors[i] = definitions[i].SizeCache; - definitions[i].SizeCache = MathUtilities.RoundLayoutValue(definitions[i].SizeCache, dpi); - } - } - definitionIndices[starDefinitionsCount++] = i; - } - else - { - double userSize = 0; - - switch (definitions[i].UserSize.GridUnitType) - { - case (GridUnitType.Pixel): - userSize = definitions[i].UserSize.Value; - break; - - case (GridUnitType.Auto): - userSize = definitions[i].MinSizeForArrange; - break; - } - - double userMaxSize; - - if (definitions[i].IsShared) - { - // overriding userMaxSize effectively prevents squishy-ness. - // this is a "solution" to avoid shared definitions from been sized to - // different final size at arrange time, if / when different grids receive - // different final sizes. - userMaxSize = userSize; - } - else - { - userMaxSize = definitions[i].UserMaxSize; - } - - definitions[i].SizeCache = Math.Max(definitions[i].MinSizeForArrange, Math.Min(userSize, userMaxSize)); - if (useLayoutRounding) - { - roundingErrors[i] = definitions[i].SizeCache; - definitions[i].SizeCache = MathUtilities.RoundLayoutValue(definitions[i].SizeCache, dpi); - } - - allPreferredArrangeSize += definitions[i].SizeCache; - definitionIndices[--nonStarIndex] = i; - } - } - - // indices should meet - Debug.Assert(nonStarIndex == starDefinitionsCount); - - if (starDefinitionsCount > 0) - { - StarDistributionOrderIndexComparer starDistributionOrderIndexComparer = new StarDistributionOrderIndexComparer(definitions); - Array.Sort(definitionIndices, 0, starDefinitionsCount, starDistributionOrderIndexComparer); - - // the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow... - // partial sum value is stored in each definition's SizeCache member. - // this way the algorithm guarantees (starValue <= definition.SizeCache) and thus - // (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. - // this is an important change from previous implementation where the following was possible: - // ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... - double allStarWeights = 0; - int i = starDefinitionsCount - 1; - do - { - allStarWeights += definitions[definitionIndices[i]].MeasureSize; - definitions[definitionIndices[i]].SizeCache = allStarWeights; - } while (--i >= 0); - - i = 0; - do - { - double resolvedSize; - double starValue = definitions[definitionIndices[i]].MeasureSize; - - if (_IsZero(starValue)) - { - resolvedSize = definitions[definitionIndices[i]].MinSizeForArrange; - } - else - { - double userSize = Math.Max(finalSize - allPreferredArrangeSize, 0.0) * (starValue / definitions[definitionIndices[i]].SizeCache); - resolvedSize = Math.Min(userSize, definitions[definitionIndices[i]].UserMaxSize); - resolvedSize = Math.Max(definitions[definitionIndices[i]].MinSizeForArrange, resolvedSize); - } - - definitions[definitionIndices[i]].SizeCache = resolvedSize; - if (useLayoutRounding) - { - roundingErrors[definitionIndices[i]] = definitions[definitionIndices[i]].SizeCache; - definitions[definitionIndices[i]].SizeCache = MathUtilities.RoundLayoutValue(definitions[definitionIndices[i]].SizeCache, dpi); - } - - allPreferredArrangeSize += definitions[definitionIndices[i]].SizeCache; - } while (++i < starDefinitionsCount); - } - - if ( allPreferredArrangeSize > finalSize - && !_AreClose(allPreferredArrangeSize, finalSize) ) - { - DistributionOrderIndexComparer distributionOrderIndexComparer = new DistributionOrderIndexComparer(definitions); - Array.Sort(definitionIndices, 0, definitions.Count, distributionOrderIndexComparer); - double sizeToDistribute = finalSize - allPreferredArrangeSize; - - for (int i = 0; i < definitions.Count; ++i) - { - int definitionIndex = definitionIndices[i]; - double final = definitions[definitionIndex].SizeCache + (sizeToDistribute / (definitions.Count - i)); - double finalOld = final; - final = Math.Max(final, definitions[definitionIndex].MinSizeForArrange); - final = Math.Min(final, definitions[definitionIndex].SizeCache); - - if (useLayoutRounding) - { - roundingErrors[definitionIndex] = final; - final = MathUtilities.RoundLayoutValue(finalOld, dpi); - final = Math.Max(final, definitions[definitionIndex].MinSizeForArrange); - final = Math.Min(final, definitions[definitionIndex].SizeCache); - } - - sizeToDistribute -= (final - definitions[definitionIndex].SizeCache); - definitions[definitionIndex].SizeCache = final; - } - - allPreferredArrangeSize = finalSize - sizeToDistribute; - } - - if (useLayoutRounding) - { - if (!_AreClose(allPreferredArrangeSize, finalSize)) - { - // Compute deltas - for (int i = 0; i < definitions.Count; ++i) - { - roundingErrors[i] = roundingErrors[i] - definitions[i].SizeCache; - definitionIndices[i] = i; - } - - // Sort rounding errors - RoundingErrorIndexComparer roundingErrorIndexComparer = new RoundingErrorIndexComparer(roundingErrors); - Array.Sort(definitionIndices, 0, definitions.Count, roundingErrorIndexComparer); - double adjustedSize = allPreferredArrangeSize; - double dpiIncrement = MathUtilities.RoundLayoutValue(1.0, dpi); - - if (allPreferredArrangeSize > finalSize) - { - int i = definitions.Count - 1; - while ((adjustedSize > finalSize && !_AreClose(adjustedSize, finalSize)) && i >= 0) - { - DefinitionBase definition = definitions[definitionIndices[i]]; - double final = definition.SizeCache - dpiIncrement; - final = Math.Max(final, definition.MinSizeForArrange); - if (final < definition.SizeCache) - { - adjustedSize -= dpiIncrement; - } - definition.SizeCache = final; - i--; - } - } - else if (allPreferredArrangeSize < finalSize) - { - int i = 0; - while ((adjustedSize < finalSize && !_AreClose(adjustedSize, finalSize)) && i < definitions.Count) - { - DefinitionBase definition = definitions[definitionIndices[i]]; - double final = definition.SizeCache + dpiIncrement; - final = Math.Max(final, definition.MinSizeForArrange); - if (final > definition.SizeCache) - { - adjustedSize += dpiIncrement; - } - definition.SizeCache = final; - i++; - } - } - } - } - - definitions[0].FinalOffset = 0.0; - for (int i = 0; i < definitions.Count; ++i) - { - definitions[(i + 1) % definitions.Count].FinalOffset = definitions[i].FinalOffset + definitions[i].SizeCache; - } + SetFinalSizeMaxDiscrepancy(definitions, finalSize, columns); } // new implementation, as of 4.7. This incorporates the same algorithm @@ -2251,7 +1762,7 @@ namespace Avalonia.Controls // Phase 1. Determine the maximum *-weight and prepare to adjust *-weights double maxStar = 0.0; - for (int i=0; i finalSize) { @@ -2694,9 +2204,9 @@ namespace Avalonia.Controls /// if the max constraint has higher discrepancy /// null if proportion doesn't fail a min or max constraint /// The discrepancy is the ratio of the proportion to the max- or min-ratio. - /// When both ratios hit the constraint, minRatio < proportion < maxRatio, + /// When both ratios hit the constraint, minRatio < proportion < maxRatio, /// and the minRatio has higher discrepancy if - /// (proportion / minRatio) > (maxRatio / proportion) + /// (proportion / minRatio) > (maxRatio / proportion) /// private static bool? Choose(double minRatio, double maxRatio, double proportion) { @@ -2782,8 +2292,8 @@ namespace Avalonia.Controls ExtendedData extData = ExtData; if (extData != null) { -// for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid (); -// for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid (); + // for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid (); + // for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid (); if (extData.TempDefinitions != null) { @@ -2800,9 +2310,9 @@ namespace Avalonia.Controls public bool ShouldSerializeColumnDefinitions() { ExtendedData extData = ExtData; - return ( extData != null - && extData.ColumnDefinitions != null - && extData.ColumnDefinitions.Count > 0 ); + return (extData != null + && extData.ColumnDefinitions != null + && extData.ColumnDefinitions.Count > 0); } /// @@ -2811,9 +2321,9 @@ namespace Avalonia.Controls public bool ShouldSerializeRowDefinitions() { ExtendedData extData = ExtData; - return ( extData != null - && extData.RowDefinitions != null - && extData.RowDefinitions.Count > 0 ); + return (extData != null + && extData.RowDefinitions != null + && extData.RowDefinitions.Count > 0); } /// @@ -2872,25 +2382,19 @@ namespace Avalonia.Controls return (flags == 0 || (_flags & flags) != 0); } - /// - /// - /// private static void OnShowGridLinesPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { Grid grid = (Grid)d; - if ( grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway - && grid.ListenToNotifications) + if (grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway + && grid.ListenToNotifications) { grid.InvalidateVisual(); } - grid.SetFlags((bool) e.NewValue, Flags.ShowGridLinesPropertyValue); + grid.SetFlags((bool)e.NewValue, Flags.ShowGridLinesPropertyValue); } - /// - /// - /// private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { Visual child = d as Visual; @@ -2898,36 +2402,20 @@ namespace Avalonia.Controls if (child != null) { Grid grid = child.GetVisualParent(); - if ( grid != null - && grid.ExtData != null - && grid.ListenToNotifications ) + if (grid != null + && grid.ExtData != null + && grid.ListenToNotifications) { grid.CellsStructureDirty = true; } } } - /* /// - /// - /// - private static bool IsIntValueNotNegative(object value) - { - return ((int)value >= 0); - } - - /// - /// - /// - private static bool IsIntValueGreaterThanZero(object value) - { - return ((int)value > 0); - }*/ - /// /// Helper for Comparer methods. /// /// - /// true iff one or both of x and y are null, in which case result holds + /// true if one or both of x and y are null, in which case result holds /// the relative sort order. /// private static bool CompareNullRefs(object x, object y, out int result) @@ -2956,12 +2444,6 @@ namespace Avalonia.Controls return (result != 2); } - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - /// /// Private version returning array of column definitions. /// @@ -2988,8 +2470,8 @@ namespace Avalonia.Controls ExtendedData extData = ExtData; int requiredLength = Math.Max(DefinitionsU.Count, DefinitionsV.Count) * 2; - if ( extData.TempDefinitions == null - || extData.TempDefinitions.Length < requiredLength ) + if (extData.TempDefinitions == null + || extData.TempDefinitions.Length < requiredLength) { WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot); if (tempDefinitionsWeakRef == null) @@ -3000,8 +2482,8 @@ namespace Avalonia.Controls else { extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target; - if ( extData.TempDefinitions == null - || extData.TempDefinitions.Length < requiredLength ) + if (extData.TempDefinitions == null + || extData.TempDefinitions.Length < requiredLength) { extData.TempDefinitions = new DefinitionBase[requiredLength]; tempDefinitionsWeakRef.Target = extData.TempDefinitions; @@ -3129,7 +2611,7 @@ namespace Avalonia.Controls /// true if d == 0. private static bool _IsZero(double d) { - return (Math.Abs(d) < c_epsilon); + return (Math.Abs(d) < double.Epsilon); } /// @@ -3140,7 +2622,7 @@ namespace Avalonia.Controls /// true if d1 == d2 private static bool _AreClose(double d1, double d2) { - return (Math.Abs(d1 - d2) < c_epsilon); + return (Math.Abs(d1 - d2) < double.Epsilon); } /// @@ -3169,13 +2651,11 @@ namespace Avalonia.Controls } } - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - private ExtendedData _data; // extended data instantiated on demand, for non-trivial case handling only - private Flags _flags; // grid validity / property caches dirtiness flags + // Extended data instantiated on demand, for non-trivial case handling only + private ExtendedData _data; + + // Grid validity / property caches dirtiness flags + private Flags _flags; private GridLinesRenderer _gridLinesRenderer; // Keeps track of definition indices. @@ -3184,29 +2664,16 @@ namespace Avalonia.Controls // Stores unrounded values and rounding errors during layout rounding. double[] _roundingErrors; - //------------------------------------------------------ - // - // Static Fields - // - //------------------------------------------------------ - private const double c_epsilon = 1e-5; // used in fp calculations - private const double c_starClip = 1e298; // used as maximum for clipping star values during normalization - private const int c_layoutLoopMaxCount = 5; // 5 is an arbitrary constant chosen to end the measure loop + // 5 is an arbitrary constant chosen to end the measure loop + private const int c_layoutLoopMaxCount = 5; + private static readonly LocalDataStoreSlot s_tempDefinitionsDataSlot = Thread.AllocateDataSlot(); private static readonly IComparer s_spanPreferredDistributionOrderComparer = new SpanPreferredDistributionOrderComparer(); private static readonly IComparer s_spanMaxDistributionOrderComparer = new SpanMaxDistributionOrderComparer(); - private static readonly IComparer s_starDistributionOrderComparer = new StarDistributionOrderComparer(); - private static readonly IComparer s_distributionOrderComparer = new DistributionOrderComparer(); private static readonly IComparer s_minRatioComparer = new MinRatioComparer(); private static readonly IComparer s_maxRatioComparer = new MaxRatioComparer(); private static readonly IComparer s_starWeightComparer = new StarWeightComparer(); - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - /// /// Extended data instantiated on demand, when grid handles non-trivial case. /// @@ -3237,34 +2704,28 @@ namespace Avalonia.Controls // * Valid???Layout flags indicate that layout time portion of the information // stored on the objects should be updated. // - ValidDefinitionsUStructure = 0x00000001, - ValidDefinitionsVStructure = 0x00000002, - ValidCellsStructure = 0x00000004, + ValidDefinitionsUStructure = 0x00000001, + ValidDefinitionsVStructure = 0x00000002, + ValidCellsStructure = 0x00000004, // // boolean properties state // - ShowGridLinesPropertyValue = 0x00000100, // show grid lines ? + ShowGridLinesPropertyValue = 0x00000100, // show grid lines ? // // boolean flags // - ListenToNotifications = 0x00001000, // "0" when all notifications are ignored - SizeToContentU = 0x00002000, // "1" if calculating to content in U direction - SizeToContentV = 0x00004000, // "1" if calculating to content in V direction - HasStarCellsU = 0x00008000, // "1" if at least one cell belongs to a Star column - HasStarCellsV = 0x00010000, // "1" if at least one cell belongs to a Star row - HasGroup3CellsInAutoRows = 0x00020000, // "1" if at least one cell of group 3 belongs to an Auto row - MeasureOverrideInProgress = 0x00040000, // "1" while in the context of Grid.MeasureOverride - ArrangeOverrideInProgress = 0x00080000, // "1" while in the context of Grid.ArrangeOverride + ListenToNotifications = 0x00001000, // "0" when all notifications are ignored + SizeToContentU = 0x00002000, // "1" if calculating to content in U direction + SizeToContentV = 0x00004000, // "1" if calculating to content in V direction + HasStarCellsU = 0x00008000, // "1" if at least one cell belongs to a Star column + HasStarCellsV = 0x00010000, // "1" if at least one cell belongs to a Star row + HasGroup3CellsInAutoRows = 0x00020000, // "1" if at least one cell of group 3 belongs to an Auto row + MeasureOverrideInProgress = 0x00040000, // "1" while in the context of Grid.MeasureOverride + ArrangeOverrideInProgress = 0x00080000, // "1" while in the context of Grid.ArrangeOverride } - //------------------------------------------------------ - // - // Properties - // - //------------------------------------------------------ - /// /// ShowGridLines property. This property is used mostly /// for simplification of visual debuggig. When it is set @@ -3289,8 +2750,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "Column", defaultValue: 0, - validate: (_, v) => { if (v >= 0) return v; - else throw new ArgumentException("Invalid Grid.Column value."); }); + validate: (_, v) => + { + if (v >= 0) return v; + else throw new ArgumentException("Invalid Grid.Column value."); + }); /// /// Row property. This is an attached property. @@ -3307,8 +2771,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "Row", defaultValue: 0, - validate: (_, v) => { if (v >= 0) return v; - else throw new ArgumentException("Invalid Grid.Row value."); }); + validate: (_, v) => + { + if (v >= 0) return v; + else throw new ArgumentException("Invalid Grid.Row value."); + }); /// /// ColumnSpan property. This is an attached property. @@ -3324,8 +2791,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "ColumnSpan", defaultValue: 1, - validate: (_, v) => { if (v >= 1) return v; - else throw new ArgumentException("Invalid Grid.ColumnSpan value."); }); + validate: (_, v) => + { + if (v >= 1) return v; + else throw new ArgumentException("Invalid Grid.ColumnSpan value."); + }); /// /// RowSpan property. This is an attached property. @@ -3341,8 +2811,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "RowSpan", defaultValue: 1, - validate: (_, v) => { if (v >= 1) return v; - else throw new ArgumentException("Invalid Grid.RowSpan value."); }); + validate: (_, v) => + { + if (v >= 1) return v; + else throw new ArgumentException("Invalid Grid.RowSpan value."); + }); /// /// IsSharedSizeScope property marks scoping element for shared size. @@ -3351,30 +2824,18 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "IsSharedSizeScope"); - //------------------------------------------------------ - // - // Internal Structures / Classes - // - //------------------------------------------------------ - /// /// LayoutTimeSizeType is used internally and reflects layout-time size type. /// [System.Flags] internal enum LayoutTimeSizeType : byte { - None = 0x00, - Pixel = 0x01, - Auto = 0x02, - Star = 0x04, + None = 0x00, + Pixel = 0x01, + Auto = 0x02, + Star = 0x04, } - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - /// /// CellCache stored calculated values of /// 1. attached cell positioning properties; @@ -3422,7 +2883,7 @@ namespace Avalonia.Controls int hash = (_start ^ (_count << 2)); if (_u) hash &= 0x7ffffff; - else hash |= 0x8000000; + else hash |= 0x8000000; return (hash); } @@ -3433,10 +2894,10 @@ namespace Avalonia.Controls public override bool Equals(object obj) { SpanKey sk = obj as SpanKey; - return ( sk != null - && sk._start == _start - && sk._count == _count - && sk._u == _u ); + return (sk != null + && sk._start == _start + && sk._count == _count + && sk._u == _u); } /// @@ -3544,51 +3005,6 @@ namespace Avalonia.Controls } } - /// - /// StarDistributionOrderComparer. - /// - private class StarDistributionOrderComparer : IComparer - { - public int Compare(object x, object y) - { - DefinitionBase definitionX = x as DefinitionBase; - DefinitionBase definitionY = y as DefinitionBase; - - int result; - - if (!CompareNullRefs(definitionX, definitionY, out result)) - { - result = definitionX.SizeCache.CompareTo(definitionY.SizeCache); - } - - return result; - } - } - - /// - /// DistributionOrderComparer. - /// - private class DistributionOrderComparer: IComparer - { - public int Compare(object x, object y) - { - DefinitionBase definitionX = x as DefinitionBase; - DefinitionBase definitionY = y as DefinitionBase; - - int result; - - if (!CompareNullRefs(definitionX, definitionY, out result)) - { - double xprime = definitionX.SizeCache - definitionX.MinSizeForArrange; - double yprime = definitionY.SizeCache - definitionY.MinSizeForArrange; - result = xprime.CompareTo(yprime); - } - - return result; - } - } - - /// /// StarDistributionOrderIndexComparer. /// @@ -3895,94 +3311,8 @@ namespace Avalonia.Controls } } - /* /// - /// Implementation of a simple enumerator of grid's logical children - /// - private class GridChildrenCollectionEnumeratorSimple : IEnumerator - { - internal GridChildrenCollectionEnumeratorSimple(Grid grid, bool includeChildren) - { - Debug.Assert(grid != null); - _currentEnumerator = -1; - _enumerator0 = new ColumnDefinitions.Enumerator(grid.ExtData != null ? grid.ExtData.ColumnDefinitions : null); - _enumerator1 = new RowDefinitions.Enumerator(grid.ExtData != null ? grid.ExtData.RowDefinitions : null); - // GridLineRenderer is NOT included into this enumerator. - _enumerator2Index = 0; - if (includeChildren) - { - _enumerator2Collection = grid.Children; - _enumerator2Count = _enumerator2Collection.Count; - } - else - { - _enumerator2Collection = null; - _enumerator2Count = 0; - } - } - - public bool MoveNext() - { - while (_currentEnumerator < 3) - { - if (_currentEnumerator >= 0) - { - switch (_currentEnumerator) - { - case (0): if (_enumerator0.MoveNext()) { _currentChild = _enumerator0.Current; return (true); } break; - case (1): if (_enumerator1.MoveNext()) { _currentChild = _enumerator1.Current; return (true); } break; - case (2): if (_enumerator2Index < _enumerator2Count) - { - _currentChild = _enumerator2Collection[_enumerator2Index]; - _enumerator2Index++; - return (true); - } - break; - } - } - _currentEnumerator++; - } - return (false); - } - - public Object Current - { - get - { - if (_currentEnumerator == -1) - { - throw new InvalidOperationException(SR.Get(SRID.EnumeratorNotStarted)); - } - if (_currentEnumerator >= 3) - { - throw new InvalidOperationException(SR.Get(SRID.EnumeratorReachedEnd)); - } - - // assert below is not true anymore since Controls allowes for null children - //Debug.Assert(_currentChild != null); - return (_currentChild); - } - } - - public void Reset() - { - _currentEnumerator = -1; - _currentChild = null; - _enumerator0.Reset(); - _enumerator1.Reset(); - _enumerator2Index = 0; - } - - private int _currentEnumerator; - private Object _currentChild; - private ColumnDefinitions.Enumerator _enumerator0; - private RowDefinitions.Enumerator _enumerator1; - private Controls _enumerator2Collection; - private int _enumerator2Index; - private int _enumerator2Count; - }*/ - /// - /// Helper to render grid lines. + /// Helper for rendering grid lines. /// internal class GridLinesRenderer : Control { @@ -3995,15 +3325,15 @@ namespace Avalonia.Controls var ds1 = new DashStyle(dashArray, 0); _oddDashPen = new Pen(Brushes.Blue, - _penWidth, - lineCap: PenLineCap.Flat, - dashStyle: ds1); + _penWidth, + lineCap: PenLineCap.Flat, + dashStyle: ds1); var ds2 = new DashStyle(dashArray, _dashLength); _evenDashPen = new Pen(Brushes.Yellow, - _penWidth, - lineCap: PenLineCap.Flat, - dashStyle: ds2); + _penWidth, + lineCap: PenLineCap.Flat, + dashStyle: ds2); } /// @@ -4052,7 +3382,6 @@ namespace Avalonia.Controls internal void UpdateRenderBounds(Size arrangeSize) { _lastArrangeSize = arrangeSize; - this.InvalidateMeasure(); this.InvalidateVisual(); } @@ -4061,6 +3390,6 @@ namespace Avalonia.Controls private const double _penWidth = 1.0; // private static readonly Pen _oddDashPen; // first pen to draw dash private static readonly Pen _evenDashPen; // second pen to draw dash - } + } } } \ No newline at end of file diff --git a/src/Avalonia.Controls/RowDefinitions.cs b/src/Avalonia.Controls/RowDefinitions.cs index 3090844251..cf72cc8ba3 100644 --- a/src/Avalonia.Controls/RowDefinitions.cs +++ b/src/Avalonia.Controls/RowDefinitions.cs @@ -14,10 +14,8 @@ namespace Avalonia.Controls /// /// Initializes a new instance of the class. /// - public RowDefinitions() + public RowDefinitions() : base() { - ResetBehavior = ResetBehavior.Remove; - CollectionChanged += OnCollectionChanged; } /// From 354a21fddb02b3f4614ae4c2acd58773f32d96c6 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 8 Jun 2019 20:50:49 +0800 Subject: [PATCH 02/11] Fix null checking --- src/Avalonia.Controls/DefinitionBase.cs | 34 +++++-------------------- src/Avalonia.Controls/Grid.cs | 28 +++----------------- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index d04578b371..dd97e7ea1e 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -110,11 +110,11 @@ namespace Avalonia.Controls /// internal void OnUserSizePropertyChanged(AvaloniaPropertyChangedEventArgs e) { - if (InParentLogicalTree) + if (Parent != null) { if (_sharedState != null) { - _sharedState.Invalidate(); + _sharedState?.Invalidate(); } else { @@ -129,21 +129,7 @@ namespace Avalonia.Controls } } } - - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static void OnUserMinSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) - { - DefinitionBase definition = (DefinitionBase)d; - - if (definition.InParentLogicalTree) - { - Grid parentGrid = (Grid)definition.Parent; - parentGrid.InvalidateMeasure(); - } - } - + /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty @@ -317,14 +303,6 @@ namespace Avalonia.Controls /// internal abstract double UserMaxSizeValueCache { get; } - /// - /// Protected. Returns true if this DefinitionBase instance is in parent's logical tree. - /// - internal bool InParentLogicalTree - { - get { return (_parentIndex != -1); } - } - internal Grid Parent { get; set; } /// @@ -349,7 +327,7 @@ namespace Avalonia.Controls { DefinitionBase definition = (DefinitionBase)d; - if (definition.InParentLogicalTree) + if (definition.Parent != null) { string sharedSizeGroupId = (string)e.NewValue; @@ -421,7 +399,7 @@ namespace Avalonia.Controls { DefinitionBase definition = (DefinitionBase)d; - if (definition.InParentLogicalTree) + if (definition.Parent != null) { SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; @@ -787,4 +765,4 @@ namespace Avalonia.Controls PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 5a44b93941..519732e36a 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -1726,7 +1726,7 @@ namespace Avalonia.Controls /// /// Array of definitions to process. /// Final size to lay out to. - /// True if sizing row definitions, false for columns + /// True if sizing row definitions, false for columns private void SetFinalSize( IReadOnlyList definitions, double finalSize, @@ -2303,29 +2303,7 @@ namespace Avalonia.Controls } } } - - /// - /// Returns true if ColumnDefinitions collection is not empty - /// - public bool ShouldSerializeColumnDefinitions() - { - ExtendedData extData = ExtData; - return (extData != null - && extData.ColumnDefinitions != null - && extData.ColumnDefinitions.Count > 0); - } - - /// - /// Returns true if RowDefinitions collection is not empty - /// - public bool ShouldSerializeRowDefinitions() - { - ExtendedData extData = ExtData; - return (extData != null - && extData.RowDefinitions != null - && extData.RowDefinitions.Count > 0); - } - + /// /// Synchronized ShowGridLines property with the state of the grid's visual collection /// by adding / removing GridLinesRenderer visual. @@ -3392,4 +3370,4 @@ namespace Avalonia.Controls private static readonly Pen _evenDashPen; // second pen to draw dash } } -} \ No newline at end of file +} From a249ff324e1e0b4f2397cbd39985ec2ec65a595e Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Tue, 11 Jun 2019 01:13:49 +0800 Subject: [PATCH 03/11] Eliminate OnUserSizePropertyChanged --- src/Avalonia.Controls/DefinitionBase.cs | 34 ------------------------- 1 file changed, 34 deletions(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index dd97e7ea1e..a68fe1265f 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -52,15 +52,6 @@ namespace Avalonia.Controls } } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) - { - if (e.Property.PropertyType == typeof(GridLength) - || e.Property.PropertyType == typeof(double)) - OnUserSizePropertyChanged(e); - - base.OnPropertyChanged(e); - } - /// /// Callback to notify about exitting model tree. /// @@ -105,31 +96,6 @@ namespace Avalonia.Controls _minSize = minSize; } - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal void OnUserSizePropertyChanged(AvaloniaPropertyChangedEventArgs e) - { - if (Parent != null) - { - if (_sharedState != null) - { - _sharedState?.Invalidate(); - } - else - { - if (((GridLength)e.OldValue).GridUnitType != ((GridLength)e.NewValue).GridUnitType) - { - Parent.Invalidate(); - } - else - { - Parent.InvalidateMeasure(); - } - } - } - } - /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty From 86a48cf7d583539744c7f82611e5b02f4e636fae Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 11 Jun 2019 19:08:25 +0300 Subject: [PATCH 04/11] Fixed #2561 --- src/Avalonia.Build.Tasks/Program.cs | 11 ++++- .../XamlIlAvaloniaPropertyHelper.cs | 2 +- .../Xaml/XamlIlTests.cs | 42 +++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Build.Tasks/Program.cs b/src/Avalonia.Build.Tasks/Program.cs index c2d0950264..d356b15408 100644 --- a/src/Avalonia.Build.Tasks/Program.cs +++ b/src/Avalonia.Build.Tasks/Program.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.IO; +using System.Linq; using Microsoft.Build.Framework; namespace Avalonia.Build.Tasks @@ -11,8 +12,14 @@ namespace Avalonia.Build.Tasks { if (args.Length != 3) { - Console.Error.WriteLine("input references output"); - return 1; + if (args.Length == 1) + args = new[] {"original.dll", "references", "out.dll"} + .Select(x => Path.Combine(args[0], x)).ToArray(); + else + { + Console.Error.WriteLine("input references output"); + return 1; + } } return new CompileAvaloniaXamlTask() diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 452bb05132..34a79a4cdc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -64,7 +64,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true); forgedReference = new XamlIlAstNamePropertyReference(lineInfo, - tref, parsedPropertyName.name, tref); + tref, parsedPropertyName.name, selectorTypeReference); } var clrProperty = diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 5e346e5289..b2cc44291d 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -207,6 +207,33 @@ namespace Avalonia.Markup.Xaml.UnitTests xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'/>", typeof(XamlIlTests).Assembly); Assert.Equal(Design.GetDataContext(loaded), SomeStaticProperty); } + + [Fact] + public void Attached_Properties_From_Static_Types_Should_Work_In_Style_Setters_Bug_2561() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + + var parsed = (Window)AvaloniaXamlLoader.Parse(@" + + + + + + + +"); + var tb = ((TextBox)parsed.Content); + parsed.Show(); + tb.ApplyTemplate(); + Assert.Equal(100, XamlIlBugTestsStaticClassWithAttachedProperty.GetTestInt(tb)); + } + } } public class XamlIlBugTestsEventHandlerCodeBehind : Window @@ -272,4 +299,19 @@ namespace Avalonia.Markup.Xaml.UnitTests { } + public static class XamlIlBugTestsStaticClassWithAttachedProperty + { + public static readonly AvaloniaProperty TestIntProperty = AvaloniaProperty + .RegisterAttached("TestInt", typeof(XamlIlBugTestsStaticClassWithAttachedProperty)); + + public static void SetTestInt(Control control, int value) + { + control.SetValue(TestIntProperty, value); + } + + public static int GetTestInt(Control control) + { + return (int)control.GetValue(TestIntProperty); + } + } } From 143b6a3476537e27ed61424258d11947f94c219c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 11 Jun 2019 21:10:41 +0300 Subject: [PATCH 05/11] Explicitly ignore Setter's property type for animations --- .../AvaloniaXamlIlLanguage.cs | 2 +- .../AvaloniaXamlIlSetterTransformer.cs | 27 ++++++-- .../AvaloniaXamlIlWellKnownTypes.cs | 2 + .../XamlIlAvaloniaPropertyHelper.cs | 66 ++++++++++++++++++- 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 581dbcdac7..d5cc93ef66 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -165,7 +165,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); if (!(node is XamlIlAstTextNode text)) throw new XamlIlLoadException("Property should be a text node", node); - result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text); + result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text, false); return true; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index 0e7ea34bb7..d548d3a188 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -16,8 +16,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (!(node is XamlIlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter")) return node; - var parent = context.ParentNodes().OfType() - .FirstOrDefault(x => x.Type.GetClrType().FullName == "Avalonia.Styling.Style"); + + // This is a hack required to get complex animations (which are also a hack) to work + var inAnimation = false; + + XamlIlAstObjectNode parent = null; + + foreach (var p in context.ParentNodes().OfType()) + { + if (p.Type.GetClrType().FullName == "Avalonia.Styling.Style") + { + parent = p; + break; + } + + if (p.Type.GetClrType().FullName == "Avalonia.Animation.Animation") + inAnimation = true; + } + if (parent == null) throw new XamlIlParseException( "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node); @@ -43,7 +59,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName, - new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]); + new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0], + // Hack to allow passing any property to an animation + inAnimation); property.Values = new List { avaloniaPropertyNode @@ -53,8 +71,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers .OfType().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value"); if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode) { - var propType = avaloniaPropertyNode.Property.Getter?.ReturnType - ?? avaloniaPropertyNode.Property.Setters.First().Parameters[0]; + var propType = avaloniaPropertyNode.AvaloniaPropertyType; if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0], propType, out var converted)) throw new XamlIlParseException( diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index b57c26c241..c054e57380 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -10,6 +10,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlIlType BindingPriority { get; } public IXamlIlType AvaloniaObjectExtensions { get; } public IXamlIlType AvaloniaProperty { get; } + public IXamlIlType AvaloniaPropertyT { get; } public IXamlIlType IBinding { get; } public IXamlIlMethod AvaloniaObjectBindMethod { get; } public IXamlIlMethod AvaloniaObjectSetValueMethod { get; } @@ -26,6 +27,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject"); AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"); + AvaloniaPropertyT = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority"); IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding"); IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable"); diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 34a79a4cdc..bf3f8958b3 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -44,8 +44,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return true; } - public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context, - string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo) + public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context, + string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo, + bool ignoreAttachedTargetType) { XamlIlAstNamePropertyReference forgedReference; @@ -63,6 +64,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions xmlOwner += parsedPropertyName.owner; var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true); + + if (ignoreAttachedTargetType) + { + var propertyFieldName = parsedPropertyName.name + "Property"; + var found = tref.Type.GetAllFields() + .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName); + if (found == null) + throw new XamlIlParseException( + $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo); + return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found); + } + forgedReference = new XamlIlAstNamePropertyReference(lineInfo, tref, parsedPropertyName.name, selectorTypeReference); } @@ -75,13 +88,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions clrProperty); } } + + interface IXamlIlAvaloniaPropertyNode : IXamlIlAstValueNode + { + IXamlIlType AvaloniaPropertyType { get; } + } - class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode + class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode { public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo) { Type = new XamlIlAstClrTypeReference(this, type, false); Property = property; + AvaloniaPropertyType = Property.Getter?.ReturnType + ?? Property.Setters.First().Parameters[0]; } public XamlIlAstClrProperty Property { get; } @@ -93,6 +113,46 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this); return XamlIlNodeEmitResult.Type(0, Type.GetClrType()); } + + public IXamlIlType AvaloniaPropertyType { get; } + } + + class XamlIlAvaloniaPropertyFieldNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode + { + private readonly IXamlIlField _field; + + public XamlIlAvaloniaPropertyFieldNode(AvaloniaXamlIlWellKnownTypes types, + IXamlIlLineInfo lineInfo, IXamlIlField field) : base(lineInfo) + { + _field = field; + var avaloniaPropertyType = field.FieldType; + while (avaloniaPropertyType != null) + { + if (avaloniaPropertyType.GenericTypeDefinition?.Equals(types.AvaloniaPropertyT) == true) + { + AvaloniaPropertyType = avaloniaPropertyType.GenericArguments[0]; + return; + } + + avaloniaPropertyType = avaloniaPropertyType.BaseType; + } + + throw new XamlIlParseException( + $"{field.Name}'s type {field.FieldType} doesn't inherit from AvaloniaProperty, make sure to use typed properties", + lineInfo); + + } + + + + public IXamlIlAstTypeReference Type => new XamlIlAstClrTypeReference(this, _field.FieldType, false); + public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + { + codeGen.Ldsfld(_field); + return XamlIlNodeEmitResult.Type(0, _field.FieldType); + } + + public IXamlIlType AvaloniaPropertyType { get; } } interface IXamlIlAvaloniaProperty From 7a99e3118e8d2d027fe9d34197e09153b0c9fdaa Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 11 Jun 2019 21:27:57 +0300 Subject: [PATCH 06/11] Always ignore target type for fully-qualified avalonia properties --- .../AvaloniaXamlIlLanguage.cs | 2 +- .../AvaloniaXamlIlSetterTransformer.cs | 24 +++--------------- .../XamlIlAvaloniaPropertyHelper.cs | 25 +++++++------------ 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index d5cc93ef66..581dbcdac7 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -165,7 +165,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); if (!(node is XamlIlAstTextNode text)) throw new XamlIlLoadException("Property should be a text node", node); - result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text, false); + result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text); return true; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs index d548d3a188..629e2562d3 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs @@ -16,24 +16,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (!(node is XamlIlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter")) return node; - - // This is a hack required to get complex animations (which are also a hack) to work - var inAnimation = false; - - XamlIlAstObjectNode parent = null; - - foreach (var p in context.ParentNodes().OfType()) - { - if (p.Type.GetClrType().FullName == "Avalonia.Styling.Style") - { - parent = p; - break; - } - - if (p.Type.GetClrType().FullName == "Avalonia.Animation.Animation") - inAnimation = true; - } + var parent = context.ParentNodes().OfType() + .FirstOrDefault(p => p.Type.GetClrType().FullName == "Avalonia.Styling.Style"); + if (parent == null) throw new XamlIlParseException( "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node); @@ -59,9 +45,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName, - new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0], - // Hack to allow passing any property to an animation - inAnimation); + new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]); property.Values = new List { avaloniaPropertyNode diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index bf3f8958b3..6fc83cb5a5 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -45,8 +45,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context, - string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo, - bool ignoreAttachedTargetType) + string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo) { XamlIlAstNamePropertyReference forgedReference; @@ -64,20 +63,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions xmlOwner += parsedPropertyName.owner; var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true); - - if (ignoreAttachedTargetType) - { - var propertyFieldName = parsedPropertyName.name + "Property"; - var found = tref.Type.GetAllFields() - .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName); - if (found == null) - throw new XamlIlParseException( - $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo); - return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found); - } - - forgedReference = new XamlIlAstNamePropertyReference(lineInfo, - tref, parsedPropertyName.name, selectorTypeReference); + + var propertyFieldName = parsedPropertyName.name + "Property"; + var found = tref.Type.GetAllFields() + .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName); + if (found == null) + throw new XamlIlParseException( + $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo); + return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found); } var clrProperty = From 57e061366ed353fef31f9b429d06b4f08f1196a0 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 11 Jun 2019 22:00:01 +0300 Subject: [PATCH 07/11] Use AvaloniaProperty in test class --- tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index b2cc44291d..5398e76f63 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -301,7 +301,7 @@ namespace Avalonia.Markup.Xaml.UnitTests public static class XamlIlBugTestsStaticClassWithAttachedProperty { - public static readonly AvaloniaProperty TestIntProperty = AvaloniaProperty + public static readonly AvaloniaProperty TestIntProperty = AvaloniaProperty .RegisterAttached("TestInt", typeof(XamlIlBugTestsStaticClassWithAttachedProperty)); public static void SetTestInt(Control control, int value) From 434af7d56db1d1ca0e91762c5e4f05fc3df1c57f Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Tue, 11 Jun 2019 13:58:50 +0200 Subject: [PATCH 08/11] Add CaretBrush property to Textbox --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 1 + .../Presenters/TextPresenter.cs | 32 +++++++++++++------ src/Avalonia.Controls/TextBox.cs | 9 ++++++ src/Avalonia.Themes.Default/TextBox.xaml | 3 +- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 0c0a4d705b..877875a2e1 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -26,6 +26,7 @@ + diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index fbdf885709..2626b67bfc 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -19,6 +19,9 @@ namespace Avalonia.Controls.Presenters public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty CaretBrushProperty = + AvaloniaProperty.Register(nameof(CaretBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( o => o.SelectionStart, @@ -35,7 +38,7 @@ namespace Avalonia.Controls.Presenters private int _selectionEnd; private bool _caretBlink; private IBrush _highlightBrush; - + static TextPresenter() { AffectsRender(PasswordCharProperty); @@ -79,6 +82,12 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } + public IBrush CaretBrush + { + get => GetValue(CaretBrushProperty); + set => SetValue(CaretBrushProperty, value); + } + public int SelectionStart { get @@ -144,16 +153,21 @@ namespace Avalonia.Controls.Presenters if (selectionStart == selectionEnd) { - var backgroundColor = (((Control)TemplatedParent).GetValue(BackgroundProperty) as SolidColorBrush)?.Color; - var caretBrush = Brushes.Black; + var caretBrush = CaretBrush; - if (backgroundColor.HasValue) + if (caretBrush is null) { - byte red = (byte)~(backgroundColor.Value.R); - byte green = (byte)~(backgroundColor.Value.G); - byte blue = (byte)~(backgroundColor.Value.B); - - caretBrush = new SolidColorBrush(Color.FromRgb(red, green, blue)); + var backgroundColor = (((Control)TemplatedParent).GetValue(BackgroundProperty) as SolidColorBrush)?.Color; + if (backgroundColor.HasValue) + { + byte red = (byte)~(backgroundColor.Value.R); + byte green = (byte)~(backgroundColor.Value.G); + byte blue = (byte)~(backgroundColor.Value.B); + + caretBrush = new SolidColorBrush(Color.FromRgb(red, green, blue)); + } + else + caretBrush = Brushes.Black; } if (_caretBlink) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d43957313e..f67b6e54a5 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -38,6 +38,9 @@ namespace Avalonia.Controls public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty CaretBrushProperty = + AvaloniaProperty.Register(nameof(CaretBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionStart), @@ -169,6 +172,12 @@ namespace Avalonia.Controls set => SetValue(PasswordCharProperty, value); } + public IBrush CaretBrush + { + get => GetValue(CaretBrushProperty); + set => SetValue(CaretBrushProperty, value); + } + public int SelectionStart { get diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 6741bdc7d9..a82ea1289b 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -44,7 +44,8 @@ SelectionEnd="{TemplateBinding SelectionEnd}" TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" - PasswordChar="{TemplateBinding PasswordChar}"/> + PasswordChar="{TemplateBinding PasswordChar}" + CaretBrush="{TemplateBinding CaretBrush}"/> From 76f9c8fdc5831c4571147cf098b082741ea49f44 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 12 Jun 2019 10:22:38 +0300 Subject: [PATCH 09/11] Removed legacy XAML loader --- .gitmodules | 3 - .../Remote/RemoteDesignerEntryPoint.cs | 6 +- .../Avalonia.Markup.Xaml.csproj | 20 +- .../AvaloniaTypeConverters.cs | 107 ----- .../AvaloniaXamlLoader.cs | 159 +------ .../Converters/AvaloniaEventConverter.cs | 99 ----- .../AvaloniaPropertyTypeConverter.cs | 1 - .../Converters/BitmapTypeConverter.cs | 3 +- .../Converters/FontFamilyTypeConverter.cs | 1 - .../Converters/IconTypeConverter.cs | 1 - .../Converters/NullableTypeConverter.cs | 89 ---- .../Converters/ParseTypeConverter.cs | 79 ---- .../Converters/SelectorTypeConverter.cs | 27 -- .../Converters/SetterValueTypeConverter.cs | 49 --- src/Markup/Avalonia.Markup.Xaml/Extensions.cs | 41 +- .../MarkupExtensions/BindingExtension.cs | 14 +- .../DynamicResourceExtension.cs | 9 +- .../RelativeSourceExtension.cs | 7 +- .../MarkupExtensions/ResourceInclude.cs | 12 +- .../StaticResourceExtension.cs | 22 +- .../MarkupExtensions/StyleIncludeExtension.cs | 9 +- .../PortableXaml/AttributeExtensions.cs | 39 -- .../AvaloniaMemberAttributeProvider.cs | 83 ---- .../PortableXaml/AvaloniaNameScope.cs | 56 --- .../AvaloniaRuntimeTypeProvider.cs | 147 ------- .../AvaloniaTypeAttributeProvider.cs | 117 ------ .../PortableXaml/AvaloniaXamlContext.cs | 31 -- .../PortableXaml/AvaloniaXamlObjectWriter.cs | 222 ---------- .../PortableXaml/AvaloniaXamlSchemaContext.cs | 327 --------------- .../PortableXaml/AvaloniaXamlType.cs | 388 ------------------ .../PortableXaml/TypeDescriptorExtensions.cs | 101 ----- .../PortableXaml/portable.xaml.github | 1 - .../Templates/TemplateContent.cs | 32 +- .../Templates/TemplateLoader.cs | 26 -- .../AvaloniaXamlIlLanguage.cs | 11 +- .../XamlIl/Runtime/XamlIlRuntimeHelpers.cs | 2 - src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs | 34 ++ .../Avalonia.DesignerSupport.TestApp/App.xaml | 6 +- .../Avalonia.DesignerSupport.TestApp.csproj | 2 +- .../MainWindow.xaml | 6 +- .../DesignerSupportTests.cs | 17 +- .../AvaloniaPropertyConverterTest.cs | 26 +- .../Xaml/BasicTests.cs | 70 ---- .../Xaml/EventTests.cs | 14 - .../Xaml/StyleTests.cs | 4 +- .../Xaml/XamlTestHelpers.cs | 3 +- 46 files changed, 108 insertions(+), 2415 deletions(-) delete mode 100644 src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs delete mode 160000 src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs diff --git a/.gitmodules b/.gitmodules index 22a241f120..10c780c09f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github"] - path = src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github - url = https://github.com/AvaloniaUI/Portable.Xaml.git [submodule "nukebuild/Numerge"] path = nukebuild/Numerge url = https://github.com/kekekeks/Numerge.git diff --git a/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs index 801ed74ca0..a0e86a53b0 100644 --- a/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs +++ b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs @@ -9,7 +9,6 @@ using Avalonia.Remote.Protocol; using Avalonia.Remote.Protocol.Designer; using Avalonia.Remote.Protocol.Viewport; using Avalonia.Threading; -using Portable.Xaml; namespace Avalonia.DesignerSupport.Remote { @@ -206,7 +205,6 @@ namespace Avalonia.DesignerSupport.Remote } catch (Exception e) { - var xamlException = e as XamlException; var xmlException = e as XmlException; s_transport.Send(new UpdateXamlResultMessage @@ -216,8 +214,8 @@ namespace Avalonia.DesignerSupport.Remote { ExceptionType = e.GetType().FullName, Message = e.Message.ToString(), - LineNumber = xamlException?.LineNumber ?? xmlException?.LineNumber, - LinePosition = xamlException?.LinePosition ?? xmlException?.LinePosition, + LineNumber = xmlException?.LineNumber, + LinePosition = xmlException?.LinePosition, } }); } diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 8ce29e5b8e..996cfdbc52 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -11,12 +11,8 @@ - - - - @@ -24,25 +20,12 @@ - - - - - - - - - - - - - @@ -52,7 +35,6 @@ - @@ -76,11 +58,11 @@ - + diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs deleted file mode 100644 index f967bdf0af..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.ComponentModel; -using System.Collections.Generic; -using System.Globalization; -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Markup.Xaml.Converters; -using Avalonia.Media.Imaging; -using Avalonia.Styling; -using Avalonia.Controls.Templates; - -namespace Avalonia.Markup.Xaml -{ - using System.Reflection; - using Avalonia.Media; - - /// - /// Maintains a repository of s for XAML parsing on top of those - /// maintained by . - /// - /// - /// The default method of defining type converters using - /// isn't powerful enough for our purposes: - /// - /// - It doesn't handle non-constructed generic types (such as ) - /// - Type converters which require XAML features cannot be defined in non-XAML assemblies and - /// so can't be referenced using - /// - Many types have a static `Parse(string)` method which can be used implicitly; this class - /// detects such methods and auto-creates a type converter - /// - public static class AvaloniaTypeConverters - { - // When adding item to that list make sure to modify AvaloniaXamlIlLanguage - private static Dictionary _converters = new Dictionary() - { - { typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) }, - { typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) }, - { typeof(IBitmap), typeof(BitmapTypeConverter) }, - { typeof(IList), typeof(PointsListTypeConverter) }, - { typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) }, - { typeof(Selector), typeof(SelectorTypeConverter) }, - { typeof(TimeSpan), typeof(TimeSpanTypeConverter) }, - { typeof(WindowIcon), typeof(IconTypeConverter) }, - { typeof(CultureInfo), typeof(CultureInfoConverter) }, - { typeof(Uri), typeof(AvaloniaUriTypeConverter) }, - { typeof(FontFamily), typeof(FontFamilyTypeConverter) }, - { typeof(EventInfo), typeof(AvaloniaEventConverter) }, - }; - - internal static Type GetBuiltinTypeConverter(Type type) - { - _converters.TryGetValue(type, out var result); - return result; - } - - /// - /// Tries to lookup a for a type. - /// - /// The type. - /// The type converter. - public static Type GetTypeConverter(Type type) - { - if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - var inner = GetTypeConverter(type.GetGenericArguments()[0]); - if (inner == null) - return null; - return typeof(NullableTypeConverter<>).MakeGenericType(inner); - } - - if (_converters.TryGetValue(type, out var result)) - { - return result; - } - - // Converters for non-constructed generic types can't be specified using - // TypeConverterAttribute. Allow them to be registered here and handle them sanely. - if (type.IsConstructedGenericType && - _converters.TryGetValue(type.GetGenericTypeDefinition(), out result)) - { - return result?.MakeGenericType(type.GetGenericArguments()); - } - - // If the type isn't a primitive or a type that XAML already handles, but has a static - // Parse method, use that - if (!type.IsPrimitive && - type != typeof(DateTime) && - type != typeof(Uri) && - ParseTypeConverter.HasParseMethod(type)) - { - result = typeof(ParseTypeConverter<>).MakeGenericType(type); - _converters.Add(type, result); - return result; - } - - _converters.Add(type, null); - return null; - } - - /// - /// Registers a type converter for a type. - /// - /// The type. Maybe be a non-constructed generic type. - /// The converter type. Maybe be a non-constructed generic type. - public static void Register(Type type, Type converterType) => _converters[type] = converterType; - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index 45424e67bb..e8f2439f46 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -15,7 +15,6 @@ using Avalonia.Controls; using Avalonia.Markup.Data; using Avalonia.Markup.Xaml.PortableXaml; using Avalonia.Platform; -using Portable.Xaml; namespace Avalonia.Markup.Xaml { @@ -26,71 +25,14 @@ namespace Avalonia.Markup.Xaml { public bool IsDesignMode { get; set; } - public static bool UseLegacyXamlLoader { get; set; } = false; - - /// - /// Initializes a new instance of the class. - /// - public AvaloniaXamlLoader() - { - } - /// /// Loads the XAML into a Avalonia component. /// /// The object to load the XAML into. public static void Load(object obj) { - Contract.Requires(obj != null); - - var loader = new AvaloniaXamlLoader(); - loader.Load(obj.GetType(), obj); - } - - /// - /// Loads the XAML for a type. - /// - /// The type. - /// - /// The optional instance into which the XAML should be loaded. - /// - /// The loaded object. - public object Load(Type type, object rootInstance = null) - { - Contract.Requires(type != null); - - // HACK: Currently Visual Studio is forcing us to change the extension of xaml files - // in certain situations, so we try to load .xaml and if that's not found we try .xaml. - // Ideally we'd be able to use .xaml everywhere - var assetLocator = AvaloniaLocator.Current.GetService(); - - if (assetLocator == null) - { - throw new InvalidOperationException( - "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); - } - - foreach (var uri in GetUrisFor(assetLocator, type)) - { - if (assetLocator.Exists(uri)) - { - using (var stream = assetLocator.Open(uri)) - { - var initialize = rootInstance as ISupportInitialize; - initialize?.BeginInit(); - try - { - return Load(stream, type.Assembly, rootInstance, uri); - } - finally - { - initialize?.EndInit(); - } - } - } - } - - throw new FileNotFoundException("Unable to find view for " + type.FullName); + throw new XamlLoadException( + $"No precompiled XAML found for {obj.GetType()}, make sure to specify x:Class and include your XAML file as AvaloniaResource"); } /// @@ -100,11 +42,8 @@ namespace Avalonia.Markup.Xaml /// /// A base URI to use if is relative. /// - /// - /// The optional instance into which the XAML should be loaded. - /// /// The loaded object. - public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) + public object Load(Uri uri, Uri baseUri = null) { Contract.Requires(uri != null); @@ -133,7 +72,7 @@ namespace Avalonia.Markup.Xaml using (var stream = asset.stream) { var absoluteUri = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri); - return Load(stream, asset.assembly, rootInstance, absoluteUri); + return Load(stream, asset.assembly, null, absoluteUri); } } @@ -166,95 +105,9 @@ namespace Avalonia.Markup.Xaml /// /// The URI of the XAML /// The loaded object. - public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null) - { - if (!UseLegacyXamlLoader) - return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, IsDesignMode); - - - var readerSettings = new XamlXmlReaderSettings() - { - BaseUri = uri, - LocalAssembly = localAssembly, - ProvideLineInfo = true, - }; - - var context = IsDesignMode ? AvaloniaXamlSchemaContext.DesignInstance : AvaloniaXamlSchemaContext.Instance; - var reader = new XamlXmlReader(stream, context, readerSettings); - - object result = LoadFromReader( - reader, - AvaloniaXamlContext.For(readerSettings, rootInstance)); - - var topLevel = result as TopLevel; - - if (topLevel != null) - { - DelayedBinding.ApplyBindings(topLevel); - } - - return result; - } - - internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null, IAmbientProvider parentAmbientProvider = null) - { - var writer = AvaloniaXamlObjectWriter.Create( - (AvaloniaXamlSchemaContext)reader.SchemaContext, - context, - parentAmbientProvider); + public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null) + => AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, IsDesignMode); - XamlServices.Transform(reader, writer); - writer.ApplyAllDelayedProperties(); - return writer.Result; - } - - internal static object LoadFromReader(XamlReader reader) - { - //return XamlServices.Load(reader); - return LoadFromReader(reader, null); - } - - - private static readonly DataContractSerializer s_xamlInfoSerializer = - new DataContractSerializer(typeof(AvaloniaResourceXamlInfo)); - /// - /// Gets the URI for a type. - /// - /// - /// The type. - /// The URI. - private static IEnumerable GetUrisFor(IAssetLoader assetLocator, Type type) - { - var asm = type.GetTypeInfo().Assembly.GetName().Name; - var xamlInfoUri = new Uri($"avares://{asm}/!AvaloniaResourceXamlInfo"); - var typeName = type.FullName; - if (typeName == null) - throw new ArgumentException("Type doesn't have a FullName"); - - if (assetLocator.Exists(xamlInfoUri)) - { - using (var xamlInfoStream = assetLocator.Open(xamlInfoUri)) - { - var assetDoc = XDocument.Load(xamlInfoStream); - XNamespace assetNs = assetDoc.Root.Attribute("xmlns").Value; - XNamespace arrayNs = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; - Dictionary xamlInfo = - assetDoc.Root.Element(assetNs + "ClassToResourcePathIndex").Elements(arrayNs + "KeyValueOfstringstring") - .ToDictionary(entry =>entry.Element(arrayNs + "Key").Value, - entry => entry.Element(arrayNs + "Value").Value); - - if (xamlInfo.TryGetValue(typeName, out var rv)) - { - yield return new Uri($"avares://{asm}{rv}"); - yield break; - } - } - } - - yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); - yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); - } - public static object Parse(string xaml, Assembly localAssembly = null) => new AvaloniaXamlLoader().Load(xaml, localAssembly); diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs deleted file mode 100644 index 665e71bfea..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Avalonia.Controls; -using Avalonia.Markup.Xaml.PortableXaml; -using Portable.Xaml; - -namespace Avalonia.Markup.Xaml.Converters -{ - internal class AvaloniaEventConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - var text = value as string; - if (text != null) - { - var rootObjectProvider = context.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; - var destinationTypeProvider = context.GetService(typeof(IDestinationTypeProvider)) as IDestinationTypeProvider; - if (rootObjectProvider != null && destinationTypeProvider != null) - { - var target = rootObjectProvider.RootObject; - var eventType = destinationTypeProvider.GetDestinationType(); - var eventParameters = eventType.GetRuntimeMethods().First(r => r.Name == "Invoke").GetParameters(); - // go in reverse to match System.Xaml behaviour - var methods = target.GetType().GetRuntimeMethods().Reverse(); - - // find based on exact match parameter types first - foreach (var method in methods) - { - if (method.Name != text) - continue; - var parameters = method.GetParameters(); - if (eventParameters.Length != parameters.Length) - continue; - if (parameters.Length == 0) - return method.CreateDelegate(eventType, target); - - for (int i = 0; i < parameters.Length; i++) - { - var param = parameters[i]; - var eventParam = eventParameters[i]; - if (param.ParameterType != eventParam.ParameterType) - break; - if (i == parameters.Length - 1) - return method.CreateDelegate(eventType, target); - } - } - - // EnhancedXaml: Find method with compatible base class parameters - foreach (var method in methods) - { - if (method.Name != text) - continue; - var parameters = method.GetParameters(); - if (parameters.Length == 0 || eventParameters.Length != parameters.Length) - continue; - - for (int i = 0; i < parameters.Length; i++) - { - var param = parameters[i]; - var eventParam = eventParameters[i]; - if (!param.ParameterType.GetTypeInfo().IsAssignableFrom(eventParam.ParameterType.GetTypeInfo())) - break; - if (i == parameters.Length - 1) - return method.CreateDelegate(eventType, target); - } - } - - var contextProvider = (IXamlSchemaContextProvider)context.GetService(typeof(IXamlSchemaContextProvider)); - var avaloniaContext = (AvaloniaXamlSchemaContext)contextProvider.SchemaContext; - - if (avaloniaContext.IsDesignMode) - { - // We want to ignore missing events in the designer, so if event handler - // wasn't found create an empty delegate. - var lambdaExpression = Expression.Lambda( - eventType, - Expression.Empty(), - eventParameters.Select(x => Expression.Parameter(x.ParameterType))); - return lambdaExpression.Compile(); - } - else - { - throw new XamlObjectWriterException($"Referenced value method {text} in type {target.GetType()} indicated by event {eventType.FullName} was not found"); - } - } - } - return base.ConvertFrom(context, culture, value); - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index 18a7fe9ab6..b42bd53619 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -11,7 +11,6 @@ using Avalonia.Markup.Xaml.Parsers; using Avalonia.Markup.Xaml.Templates; using Avalonia.Styling; using Avalonia.Utilities; -using Portable.Xaml.ComponentModel; namespace Avalonia.Markup.Xaml.Converters { diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs index bfee7b953b..c75c54554e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs @@ -8,8 +8,7 @@ using Avalonia.Platform; namespace Avalonia.Markup.Xaml.Converters { - using Portable.Xaml.ComponentModel; - using System.ComponentModel; + using System.ComponentModel; public class BitmapTypeConverter : TypeConverter { diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs index 863e8fbbce..e92c155773 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs @@ -7,7 +7,6 @@ using System.Globalization; using Avalonia.Media; -using Portable.Xaml.ComponentModel; namespace Avalonia.Markup.Xaml.Converters { diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs index f3972ffe18..3a2f41bd3d 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs @@ -9,7 +9,6 @@ using System.Globalization; namespace Avalonia.Markup.Xaml.Converters { - using Portable.Xaml.ComponentModel; using System.ComponentModel; public class IconTypeConverter : TypeConverter diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs deleted file mode 100644 index 5e7a31da56..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.Globalization; - -namespace Avalonia.Markup.Xaml.Converters -{ - public class NullableTypeConverter : TypeConverter where T : TypeConverter, new() - { - private TypeConverter _inner; - - public NullableTypeConverter() - { - _inner = new T(); - } - - public NullableTypeConverter(TypeConverter inner) - { - _inner = inner; - } - - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value == null) - return null; - return _inner.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value == null) - return null; - if (value as string == "") - return null; - return _inner.ConvertFrom(context, culture, value); - } - - public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) - { - return _inner.CreateInstance(context, propertyValues); - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) - { - return _inner.GetStandardValuesSupported(context); - } - - public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) - { - return _inner.GetStandardValuesExclusive(context); - } - - public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) - { - return _inner.GetCreateInstanceSupported(context); - } - - public override bool GetPropertiesSupported(ITypeDescriptorContext context) - { - return _inner.GetPropertiesSupported(context); - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) - { - return _inner.GetStandardValues(context); - } - - public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) - { - return _inner.GetProperties(context, value, attributes); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return _inner.CanConvertTo(context, destinationType); - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return _inner.CanConvertFrom(context, sourceType); - } - - public override bool IsValid(ITypeDescriptorContext context, object value) - { - return _inner.IsValid(context, value); - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs deleted file mode 100644 index bfb446fa15..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Reflection; - -namespace Avalonia.Markup.Xaml.Converters -{ - /// - /// Base class for type converters which call a static Parse method. - /// - public abstract class ParseTypeConverter : TypeConverter - { - protected const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static; - protected static readonly Type[] StringParameter = new[] { typeof(string) }; - protected static readonly Type[] StringIFormatProviderParameters = new[] { typeof(string), typeof(IFormatProvider) }; - - /// - /// Checks whether a type has a suitable Parse method. - /// - /// The type. - /// True if the type has a suitable parse method, otherwise false. - public static bool HasParseMethod(Type type) - { - return type.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null) != null || - type.GetMethod("Parse", PublicStatic, null, StringParameter, null) != null; - } - } - - /// - /// A type converter which calls a static Parse method. - /// - /// The type with the Parse method. - public class ParseTypeConverter : ParseTypeConverter - { - private static Func _parse; - private static Func _parseWithFormat; - - static ParseTypeConverter() - { - var method = typeof(T).GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null); - - if (method != null) - { - _parseWithFormat = (Func)method - .CreateDelegate(typeof(Func)); - return; - } - - method = typeof(T).GetMethod("Parse", PublicStatic, null, StringParameter, null); - - if (method != null) - { - _parse = (Func)method.CreateDelegate(typeof(Func)); - } - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value != null) - { - if (_parse != null) - { - return _parse(value.ToString()); - } - else if (_parseWithFormat != null) - { - return _parseWithFormat(value.ToString(), culture); - } - } - - return null; - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs deleted file mode 100644 index 54234fe406..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using Avalonia.Markup.Parsers; - -namespace Avalonia.Markup.Xaml.Converters -{ - using Portable.Xaml.ComponentModel; - using System.ComponentModel; - - public class SelectorTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - var parser = new SelectorParser(context.ResolveType); - - return parser.Parse((string)value); - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs deleted file mode 100644 index 81cda6db1f..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Avalonia.Styling; -using Portable.Xaml; -using Portable.Xaml.ComponentModel; -using System.ComponentModel; -using Portable.Xaml.Markup; -using System; -using System.Globalization; - -namespace Avalonia.Markup.Xaml.Converters -{ - public class SetterValueTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - object setter = context.GetService().TargetObject; - var schemaContext = context.GetService().SchemaContext; - - return ConvertSetterValue(context, schemaContext, culture, (setter as Setter), value); - } - - [Obsolete("TODO: try assosiate Setter.Value property with SetterValueTypeConverter, so far coouldn't make it :(")] - internal static object ConvertSetterValue(ITypeDescriptorContext dcontext, XamlSchemaContext context, CultureInfo info, Setter setter, object value) - { - Type targetType = setter?.Property?.PropertyType; - - if (targetType == null) - { - return value; - } - - var ttConv = context.GetXamlType(targetType)?.TypeConverter?.ConverterInstance; - - if (ttConv != null) - { - value = ttConv.ConvertFromString(dcontext, info, value as string); - } - - return value; - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Extensions.cs b/src/Markup/Avalonia.Markup.Xaml/Extensions.cs index c6b914ba72..fe3fd44c1c 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Extensions.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Extensions.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.Runtime; -using Portable.Xaml; -using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml { @@ -13,42 +11,19 @@ namespace Avalonia.Markup.Xaml public static T GetService(this IServiceProvider sp) => (T)sp?.GetService(typeof(T)); - public static Uri GetContextBaseUri(this IServiceProvider ctx) - { - var properService = ctx.GetService(); - if (properService != null) - return properService.BaseUri; - // Ugly hack with casts - return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetBaseUri((ITypeDescriptorContext)ctx); - } + public static Uri GetContextBaseUri(this IServiceProvider ctx) => ctx.GetService().BaseUri; - public static T GetFirstParent(this IServiceProvider ctx) where T : class - { - var parentStack = ctx.GetService(); - if (parentStack != null) - return parentStack.Parents.OfType().FirstOrDefault(); - return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetFirstAmbientValue((ITypeDescriptorContext)ctx); - } - - public static T GetLastParent(this IServiceProvider ctx) where T : class - { - var parentStack = ctx.GetService(); - if (parentStack != null) - return parentStack.Parents.OfType().LastOrDefault(); - return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetLastOrDefaultAmbientValue( - (ITypeDescriptorContext)ctx); - } + public static T GetFirstParent(this IServiceProvider ctx) where T : class + => ctx.GetService().Parents.OfType().FirstOrDefault(); + + public static T GetLastParent(this IServiceProvider ctx) where T : class + => ctx.GetService().Parents.OfType().LastOrDefault(); public static IEnumerable GetParents(this IServiceProvider sp) { - var stack = sp.GetService(); - if (stack != null) - return stack.Parents.OfType(); + return sp.GetService().Parents.OfType(); + - var context = (ITypeDescriptorContext)sp; - var schemaContext = context.GetService().SchemaContext; - var ambientProvider = context.GetService(); - return ambientProvider.GetAllAmbientValues(schemaContext.GetXamlType(typeof(T))).OfType(); } public static Type ResolveType(this IServiceProvider ctx, string namespacePrefix, string type) diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs index 223716ae3b..726f4221f8 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs @@ -10,14 +10,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions using Avalonia.Data.Converters; using Avalonia.Markup.Data; using Avalonia.Styling; - using Portable.Xaml; - using Portable.Xaml.ComponentModel; - using Portable.Xaml.Markup; - using PortableXaml; using System.ComponentModel; - [MarkupExtensionReturnType(typeof(IBinding))] - public class BindingExtension : MarkupExtension + public class BindingExtension { public BindingExtension() { @@ -28,12 +23,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions Path = path; } - public override object ProvideValue(IServiceProvider serviceProvider) - { - return ProvideTypedValue(serviceProvider); - } - - public Binding ProvideTypedValue(IServiceProvider serviceProvider) + public Binding ProvideValue(IServiceProvider serviceProvider) { var descriptorContext = (ITypeDescriptorContext)serviceProvider; diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs index 48e55dc251..0a9289bec9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs @@ -7,13 +7,10 @@ using System.Linq; using System.Reactive.Linq; using Avalonia.Controls; using Avalonia.Data; -using Portable.Xaml; -using Portable.Xaml.ComponentModel; -using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml.MarkupExtensions { - public class DynamicResourceExtension : MarkupExtension, IBinding + public class DynamicResourceExtension : IBinding { private IResourceNode _anchor; @@ -28,9 +25,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public object ResourceKey { get; set; } - public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider); - - public IBinding ProvideTypedValue(IServiceProvider serviceProvider) + public IBinding ProvideValue(IServiceProvider serviceProvider) { var provideTarget = serviceProvider.GetService(); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs index 2f7256fa22..f690a5ff0e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs @@ -3,11 +3,10 @@ using System; using Avalonia.Data; -using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml.MarkupExtensions { - public class RelativeSourceExtension : MarkupExtension + public class RelativeSourceExtension { public RelativeSourceExtension() { @@ -18,7 +17,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions Mode = mode; } - public override object ProvideValue(IServiceProvider serviceProvider) + public RelativeSource ProvideValue(IServiceProvider serviceProvider) { return new RelativeSource { @@ -38,4 +37,4 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public int AncestorLevel { get; set; } = 1; } -} \ No newline at end of file +} diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs index 323a341f6a..3525628a79 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs @@ -1,15 +1,13 @@ using System; using System.ComponentModel; using Avalonia.Controls; -using Portable.Xaml.ComponentModel; -using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml.MarkupExtensions { /// /// Loads a resource dictionary from a specified URL. /// - public class ResourceInclude : MarkupExtension, IResourceProvider + public class ResourceInclude :IResourceProvider { private Uri _baseUri; private IResourceDictionary _loaded; @@ -52,13 +50,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions return Loaded.TryGetResource(key, out value); } - /// - public override object ProvideValue(IServiceProvider serviceProvider) - { - return ProvideTypedValue(serviceProvider); - } - - public ResourceInclude ProvideTypedValue(IServiceProvider serviceProvider) + public ResourceInclude ProvideValue(IServiceProvider serviceProvider) { var tdc = (ITypeDescriptorContext)serviceProvider; _baseUri = tdc?.GetContextBaseUri(); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index ea913db598..d6b170ae9d 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -7,13 +7,10 @@ using System.ComponentModel; using System.Reflection; using Avalonia.Controls; using Avalonia.Markup.Data; -using Portable.Xaml; -using Portable.Xaml.ComponentModel; -using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml.MarkupExtensions { - public class StaticResourceExtension : MarkupExtension + public class StaticResourceExtension { public StaticResourceExtension() { @@ -26,26 +23,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public string ResourceKey { get; set; } - public override object ProvideValue(IServiceProvider serviceProvider) + public object ProvideValue(IServiceProvider serviceProvider) { - - // Look upwards though the ambient context for IResourceProviders which might be able // to give us the resource. foreach (var resourceProvider in serviceProvider.GetParents()) { - // We override XamlType.CanAssignTo in BindingXamlType so the results we get back - // from GetAllAmbientValues aren't necessarily of the correct type. - - if (AvaloniaXamlLoader.UseLegacyXamlLoader - && resourceProvider is IControl control && control.StylingParent != null) - { - // If we've got to a control that has a StylingParent then it's probably - // a top level control and its StylingParent is pointing to the global - // styles. If this is case just do a FindResource on it. - return control.FindResource(ResourceKey); - } - else if (resourceProvider.TryGetResource(ResourceKey, out var value)) + if (resourceProvider.TryGetResource(ResourceKey, out var value)) { return value; } diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs index d9345738fc..a323050c31 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs @@ -3,23 +3,18 @@ using Avalonia.Markup.Xaml.Styling; using Avalonia.Styling; -using Portable.Xaml; -using Portable.Xaml.ComponentModel; using System.ComponentModel; -using Portable.Xaml.Markup; using System; namespace Avalonia.Markup.Xaml.MarkupExtensions { - [MarkupExtensionReturnType(typeof(IStyle))] - public class StyleIncludeExtension : MarkupExtension + public class StyleIncludeExtension { public StyleIncludeExtension() { } - public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider); - public IStyle ProvideTypedValue(IServiceProvider serviceProvider) + public IStyle ProvideValue(IServiceProvider serviceProvider) { return new StyleInclude(serviceProvider.GetContextBaseUri()) { Source = Source }; } diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs deleted file mode 100644 index 2a23b7e068..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Avalonia.Markup.Xaml.Templates; -using avm = Avalonia.Metadata; -using pm = Portable.Xaml.Markup; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - internal static class AttributeExtensions - { - public static pm.XamlDeferLoadAttribute ToPortableXaml(this avm.TemplateContentAttribute attrib) - { - if (attrib == null) - { - return null; - } - - return new pm.XamlDeferLoadAttribute(typeof(TemplateLoader), typeof(TemplateContent)); - } - - public static pm.AmbientAttribute ToPortableXaml(this avm.AmbientAttribute attrib) - { - if (attrib == null) - { - return null; - } - - return new pm.AmbientAttribute(); - } - - public static pm.DependsOnAttribute ToPortableXaml(this avm.DependsOnAttribute attrib) - { - if (attrib == null) - { - return null; - } - - return new pm.DependsOnAttribute(attrib.Name); - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs deleted file mode 100644 index 529cbab938..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Avalonia.Markup.Xaml.Converters; -using Avalonia.Styling; -using Portable.Xaml.ComponentModel; -using System.ComponentModel; -using System; -using System.Linq; -using System.Reflection; -using avm = Avalonia.Metadata; -using pm = Portable.Xaml.Markup; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - public class AvaloniaMemberAttributeProvider : ICustomAttributeProvider - { - public AvaloniaMemberAttributeProvider(MemberInfo info) - { - _info = info; - } - - public object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public object[] GetCustomAttributes(Type attributeType, bool inherit) - { - Attribute result = null; - - if (attributeType == typeof(pm.XamlDeferLoadAttribute)) - { - result = _info.GetCustomAttribute(inherit) - .ToPortableXaml(); - } - else if (attributeType == typeof(pm.AmbientAttribute)) - { - result = _info.GetCustomAttribute(inherit) - .ToPortableXaml(); - } - else if (attributeType == typeof(pm.DependsOnAttribute)) - { - result = _info.GetCustomAttribute(inherit) - .ToPortableXaml(); - } - else if (attributeType == typeof(TypeConverterAttribute) && - _info.DeclaringType == typeof(Setter) && - _info.Name == nameof(Setter.Value)) - { - //actually it never comes here looks like if property type is object - //Portable.Xaml is not searching for Type Converter - result = new TypeConverterAttribute(typeof(SetterValueTypeConverter)); - } - else if (attributeType == typeof(TypeConverterAttribute) && _info is EventInfo) - { - // If a type converter for `EventInfo` is registered, then use that to convert - // event handler values. This is used by the designer to override the lookup - // for event handlers with a null handler. - var eventConverter = AvaloniaTypeConverters.GetTypeConverter(typeof(EventInfo)); - - if (eventConverter != null) - { - result = new TypeConverterAttribute(eventConverter); - } - } - - if (result == null) - { - var attr = _info.GetCustomAttributes(attributeType, inherit); - return (attr as object[]) ?? attr.ToArray(); - } - else - { - return new object[] { result }; - } - } - - public bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - private readonly MemberInfo _info; - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs deleted file mode 100644 index 6f855bafa1..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using Avalonia.Controls; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - internal class AvaloniaNameScope : Portable.Xaml.Markup.INameScope - { - public object Instance { get; set; } - - private Dictionary _names = new Dictionary(); - - public object FindName(string name) - { - object result; - if (_names.TryGetValue(name, out result)) - return result; - return null; - } - - public void RegisterName(string name, object scopedElement) - { - if (scopedElement != null) - _names.Add(name, scopedElement); - - //TODO: ??? - //var control = scopedElement as Control; - - //if (control != null) - //{ - // var nameScope = (Instance as INameScope) ?? control.FindNameScope(); - - // if (nameScope != null) - // { - // nameScope.Register(name, scopedElement); - // } - //} - } - - public void UnregisterName(string name) - { - } - - public void RegisterOnNameScope(object target) - { - var nameScope = target as INameScope; - - if (nameScope != null) - { - foreach (var v in _names) - { - nameScope.Register(v.Key, v.Value); - } - } - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs deleted file mode 100644 index eb52e317b8..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Avalonia.Controls; -using Avalonia.Data; -using Avalonia.Markup.Xaml.Templates; -using Avalonia.Media; -using Avalonia.Metadata; -using Avalonia.Platform; -using Avalonia.Styling; - -namespace Avalonia.Markup.Xaml.Context -{ - using ClrNamespaceInfo = Tuple; - - public interface IRuntimeTypeProvider - { - Type FindType(string xamlNamespace, string name, Type[] genArgs); - - IEnumerable ReferencedAssemblies { get; } - } - - public class AvaloniaRuntimeTypeProvider : IRuntimeTypeProvider - { - private const string ClrNamespace = "clr-namespace:"; - // private const string AvaloniaNs = "https://github.com/avaloniaui"; - - private static readonly IEnumerable ForcedAssemblies = new[] - { - typeof(AvaloniaObject).GetTypeInfo().Assembly, - typeof(Animation.Animation).GetTypeInfo().Assembly, - typeof(Control).GetTypeInfo().Assembly, - typeof(Style).GetTypeInfo().Assembly, - typeof(DataTemplate).GetTypeInfo().Assembly, - typeof(SolidColorBrush).GetTypeInfo().Assembly, - typeof(Binding).GetTypeInfo().Assembly, - }; - - private Dictionary> _namespaces = new Dictionary>(); - - private List _scanned = new List(); - - public IEnumerable ReferencedAssemblies => _scanned; - - public AvaloniaRuntimeTypeProvider() - { - ScanAssemblies(ForcedAssemblies); - ScanNewAssemblies(); - } - - private static bool IsClrNamespace(string ns) - { - return ns.StartsWith(ClrNamespace); - } - - private static Assembly GetAssembly(string assemblyName) - { - return Assembly.Load(new AssemblyName(assemblyName)); - } - - private void ScanAssemblies(IEnumerable assemblies) - { - foreach (var assembly in assemblies) - { - var namespaces = assembly.GetCustomAttributes() - .Select(x => new { x.XmlNamespace, x.ClrNamespace }) - .GroupBy(x => x.XmlNamespace); - - foreach (var nsa in namespaces) - { - HashSet reg; - - if (!_namespaces.TryGetValue(nsa.Key, out reg)) - { - _namespaces[nsa.Key] = reg = new HashSet>(); - } - - foreach (var child in nsa) - { - reg.Add(new ClrNamespaceInfo(child.ClrNamespace, assembly)); - } - } - - _scanned.Add(assembly); - } - } - - private void ScanNewAssemblies() - { - IEnumerable assemblies = AppDomain.CurrentDomain.GetAssemblies(); - - if (assemblies != null) - { - assemblies = assemblies.Except(_scanned); - ScanAssemblies(assemblies); - } - } - - private Dictionary _typeCache = new Dictionary(); - - public Type FindType(string xamlNamespace, string name, Type[] genArgs) - { - if (IsClrNamespace(xamlNamespace)) - { - //we need to handle only xaml url namespaces for avalonia, - //the other namespaces are handled well in portable.xaml - return null; - } - - string key = $"{xamlNamespace}:{name}"; - - Type type; - - if (_typeCache.TryGetValue(key, out type)) - { - return type; - } - - HashSet reg; - - if (!_namespaces.TryGetValue(xamlNamespace, out reg)) - { - return null; - } - - if (genArgs != null) - name += "`" + genArgs.Length; - - foreach (var ns in reg) - { - var n = ns.Item1 + "." + name; - var t = ns.Item2.GetType(n); - if (t != null) - { - _typeCache[key] = t; - return t; - } - } - - return null; - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs deleted file mode 100644 index 7558a5df0b..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Portable.Xaml.ComponentModel; -using System.ComponentModel; -using System; -using System.Linq; -using System.Reflection; -using avm = Avalonia.Metadata; -using pm = Portable.Xaml.Markup; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - internal class AvaloniaTypeAttributeProvider : ICustomAttributeProvider - { - public AvaloniaTypeAttributeProvider(Type type) - { - _type = type; - } - - public object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public object[] GetCustomAttributes(Type attributeType, bool inherit) - { - Attribute result = null; - - var ti = _type.GetTypeInfo(); - - if (attributeType == typeof(pm.ContentPropertyAttribute)) - { - result = GetContentPropertyAttribute(inherit); - } - else if (attributeType == typeof(pm.RuntimeNamePropertyAttribute)) - { - if (_namedType.IsAssignableFrom(ti)) - { - result = new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name)); - } - } - else if (attributeType == typeof(TypeConverterAttribute)) - { - var builtin = AvaloniaTypeConverters.GetBuiltinTypeConverter(_type); - if (builtin != null) - result = new TypeConverterAttribute(builtin); - result = result ?? ti.GetCustomAttribute(attributeType, inherit); - - if (result == null) - { - var convType = AvaloniaTypeConverters.GetTypeConverter(_type); - - if (convType != null) - { - result = new TypeConverterAttribute(convType); - } - } - } - else if (attributeType == typeof(pm.AmbientAttribute)) - { - result = ti.GetCustomAttribute(inherit) - .ToPortableXaml(); - } - - if (result == null) - { - var attr = ti.GetCustomAttributes(attributeType, inherit); - return (attr as object[]) ?? attr.ToArray(); - } - else - { - return new object[] { result }; - } - } - - public bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - private readonly TypeInfo _namedType = typeof(INamed).GetTypeInfo(); - - private readonly Type _type; - - private Attribute GetContentPropertyAttribute(bool inherit) - { - var type = _type; - - while (type != null) - { - var properties = type.GetTypeInfo().DeclaredProperties - .Where(x => x.GetCustomAttribute() != null); - string result = null; - - foreach (var property in properties) - { - if (result != null) - { - throw new Exception($"Content property defined more than once on {type}."); - } - - result = property.Name; - } - - if (result != null) - { - return new pm.ContentPropertyAttribute(result); - } - - type = inherit ? type.GetTypeInfo().BaseType : null; - } - - return null; - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs deleted file mode 100644 index c159b551b7..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Portable.Xaml; -using Portable.Xaml.Markup; -using System; -using System.Reflection; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - public class AvaloniaXamlContext : IUriContext - { - private AvaloniaXamlContext() - { - } - - public Assembly LocalAssembly { get; private set; } - - public Uri BaseUri { get; set; } - - public object RootInstance { get; private set; } - - internal static AvaloniaXamlContext For(XamlXmlReaderSettings sett, - object rootInstance) - { - return new AvaloniaXamlContext() - { - BaseUri = sett.BaseUri, - LocalAssembly = sett.LocalAssembly, - RootInstance = rootInstance - }; - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs deleted file mode 100644 index 9fa6c26c35..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Avalonia.Data; -using Portable.Xaml; -using Portable.Xaml.ComponentModel; -using System.ComponentModel; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Avalonia.Controls; -using Portable.Xaml.Schema; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - class AvaloniaXamlObjectWriter : XamlObjectWriter - { - private static Dictionary DesignDirectives = new Dictionary - { - ["DataContext"] = "DataContext", - ["DesignWidth"] = "Width", ["DesignHeight"] = "Height", ["PreviewWith"] = "PreviewWith" - } - .ToDictionary(p => new XamlDirective( - new[] {"http://schemas.microsoft.com/expression/blend/2008"}, p.Key, - XamlLanguage.Object, null, AllowedMemberLocations.Attribute), p => p.Value); - - private readonly AvaloniaXamlSchemaContext _schemaContext; - - public static AvaloniaXamlObjectWriter Create( - AvaloniaXamlSchemaContext schemaContext, - AvaloniaXamlContext context, - IAmbientProvider parentAmbientProvider = null) - { - var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance }; - - var writerSettings = new XamlObjectWriterSettings() - { - ExternalNameScope = nameScope, - RegisterNamesOnExternalNamescope = true, - RootObjectInstance = context?.RootInstance - }; - - return new AvaloniaXamlObjectWriter(schemaContext, - writerSettings.WithContext(context), - nameScope, - parentAmbientProvider); - } - - private readonly DelayedValuesHelper _delayedValuesHelper = new DelayedValuesHelper(); - - private AvaloniaNameScope _nameScope; - - private AvaloniaXamlObjectWriter( - AvaloniaXamlSchemaContext schemaContext, - XamlObjectWriterSettings settings, - AvaloniaNameScope nameScope, - IAmbientProvider parentAmbientProvider) - : base(schemaContext, settings, parentAmbientProvider) - { - _nameScope = nameScope; - _schemaContext = schemaContext; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (_nameScope != null && Result != null) - { - _nameScope.RegisterOnNameScope(Result); - } - } - - base.Dispose(disposing); - } - - public void ApplyAllDelayedProperties() - { - //HACK: We need this because Begin/EndInit ordering is broken - _delayedValuesHelper.ApplyAll(); - } - - protected internal override void OnAfterProperties(object value) - { - _delayedValuesHelper.EndInit(value); - - base.OnAfterProperties(value); - } - - protected internal override void OnBeforeProperties(object value) - { - if (value != null) - _delayedValuesHelper.BeginInit(value); - - base.OnBeforeProperties(value); - } - - protected internal override bool OnSetValue(object target, XamlMember member, object value) - { - if (_delayedValuesHelper.TryAdd(target, member, value)) - { - return true; - } - - return base.OnSetValue(target, member, value); - } - - public override void WriteStartMember(XamlMember property) - { - foreach(var d in DesignDirectives) - if (property == d.Key && _schemaContext.IsDesignMode) - { - base.WriteStartMember(new XamlMember(d.Value, - typeof(Design).GetMethod("Get" + d.Value, BindingFlags.Static | BindingFlags.Public), - typeof(Design).GetMethod("Set" + d.Value, BindingFlags.Static | BindingFlags.Public), - SchemaContext)); - return; - } - base.WriteStartMember(property); - } - - private class DelayedValuesHelper - { - private int _cnt; - - private HashSet _targets = new HashSet(); - - private IList _values = new List(); - - private IEnumerable Values => _values; - - public void BeginInit(object target) - { - ++_cnt; - - AddTargetIfNeeded(target); - } - - public void EndInit(object target) - { - --_cnt; - - if (_cnt == 0) - { - ApplyAll(); - } - } - - public bool TryAdd(object target, XamlMember member, object value) - { - if (value is IBinding) - { - Add(new DelayedValue(target, member, value)); - - return true; - } - - return false; - } - - private void Add(DelayedValue value) - { - _values.Add(value); - - var target = value.Target; - - if (!_targets.Contains(value.Target)) - { - _targets.Add(target); - (target as ISupportInitialize)?.BeginInit(); - } - } - - private void AddTargetIfNeeded(object target) - { - if (!_targets.Contains(target)) - { - Add(new DelayedValue(target, null, null)); - } - } - - public void ApplyAll() - { - //TODO: revisit this - //apply delayed values and clear - //that's the last object let's set all delayed bindings - foreach (var dv in Values.Where(v => v.Member != null)) - { - dv.Member.Invoker.SetValue(dv.Target, dv.Value); - } - - //TODO: check/add some order of end init - //currently we are sending end init in the order of - //objects creation - foreach (var v in Values) - { - var target = v.Target; - - if (_targets.Contains(target)) - { - _targets.Remove(target); - (target as ISupportInitialize)?.EndInit(); - } - } - - _targets.Clear(); - _values.Clear(); - } - - private class DelayedValue - { - public DelayedValue(object target, XamlMember member, object value) - { - Target = target; - Member = member; - Value = value; - } - - public XamlMember Member { get; } - public object Target { get; } - public object Value { get; } - } - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs deleted file mode 100644 index 326db884a6..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Avalonia.Data; -using Avalonia.Markup.Xaml.Context; -using Avalonia.Markup.Xaml.MarkupExtensions; -using Avalonia.Markup.Xaml.Styling; -using Portable.Xaml; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - internal class AvaloniaXamlSchemaContext : XamlSchemaContext - { - private static AvaloniaXamlSchemaContext s_instance; - private static AvaloniaXamlSchemaContext s_designInstance; - - public static AvaloniaXamlSchemaContext Instance - { - get - { - if (s_instance == null) - { - s_instance = Create(); - } - - return s_instance; - } - } - - public static AvaloniaXamlSchemaContext DesignInstance - { - get - { - if (s_designInstance == null) - { - s_designInstance = Create(); - s_designInstance.IsDesignMode = true; - } - - return s_designInstance; - } - } - - public bool IsDesignMode { get; private set; } - public static AvaloniaXamlSchemaContext Create(IRuntimeTypeProvider typeProvider = null) - { - return new AvaloniaXamlSchemaContext(typeProvider ?? new AvaloniaRuntimeTypeProvider()); - } - - private AvaloniaXamlSchemaContext(IRuntimeTypeProvider typeProvider) - //better not set the references assemblies - //TODO: check this on iOS - //: base(typeProvider.ReferencedAssemblies) - { - Contract.Requires(typeProvider != null); - - _avaloniaTypeProvider = typeProvider; - } - - private IRuntimeTypeProvider _avaloniaTypeProvider; - - protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments) - { - XamlType type = null; - try - { - type = ResolveXamlTypeName(xamlNamespace, name, typeArguments, false); - - if (type == null) - { - type = base.GetXamlType(xamlNamespace, name, typeArguments); - } - } - catch (Exception e) - { - //TODO: log or wrap exception - throw e; - } - return type; - } - - private XamlType ResolveXamlTypeName(string xmlNamespace, string xmlLocalName, XamlType[] typeArguments, bool required) - { - Type[] genArgs = null; - if (typeArguments != null && typeArguments.Any()) - { - genArgs = typeArguments.Select(t => t?.UnderlyingType).ToArray(); - - if (genArgs.Any(t => t == null)) - { - return null; - } - } - - // MarkupExtension type could omit "Extension" part in XML name. - Type type = _avaloniaTypeProvider.FindType(xmlNamespace, - xmlLocalName, - genArgs) ?? - _avaloniaTypeProvider.FindType(xmlNamespace, - xmlLocalName + "Extension", - genArgs); - - if (type != null) - { - Type extType; - if (_wellKnownExtensionTypes.TryGetValue(type, out extType)) - { - type = extType; - } - } - - if (type == null) - { - //let's try the simple types - //in Portable xaml like xmlns:sys='clr-namespace:System;assembly=mscorlib' - //and sys:Double is not resolved properly - return ResolveSimpleTypeName(xmlNamespace, xmlLocalName); - } - - return GetXamlType(type); - } - - #region Workaround for bug in Portablexaml system types like double,int etc ... - - private static Type[] _simpleTypes = new Type[] - { - typeof(bool), - typeof(byte), - typeof(char), - typeof(decimal), - typeof(double), - typeof(Int16), - typeof(Int32), - typeof(Int64), - typeof(float), - typeof(string), - typeof(TimeSpan), - typeof(Uri), - }; - - private static Dictionary, XamlType> _simpleXamlTypes; - - //in Portable xaml like xmlns:sys='clr-namespace:System;assembly=mscorlib' - //and sys:Double is not resolved properly - [Obsolete("TODO: remove once it's fixed in Portable.xaml")] - private static XamlType ResolveSimpleTypeName(string xmlNamespace, string xmlLocalName) - { - if (_simpleXamlTypes == null) - { - _simpleXamlTypes = new Dictionary, XamlType>(); - - foreach (var type in _simpleTypes) - { - string asmName = type.GetTypeInfo().Assembly.GetName().Name; - string ns = $"clr-namespace:{type.Namespace};assembly={asmName}"; - var xamlType = XamlLanguage.AllTypes.First(t => t.UnderlyingType == type); - _simpleXamlTypes.Add(new Tuple(ns, type.Name), xamlType); - } - } - - XamlType result; - - var key = new Tuple(xmlNamespace, xmlLocalName); - - _simpleXamlTypes.TryGetValue(key, out result); - - return result; - } - - #endregion Workaround for bug in Portablexaml system types like double,int etc ... - - protected internal override ICustomAttributeProvider GetCustomAttributeProvider(Type type) - => new AvaloniaTypeAttributeProvider(type); - - protected internal override ICustomAttributeProvider GetCustomAttributeProvider(MemberInfo member) - => new AvaloniaMemberAttributeProvider(member); - - public override XamlType GetXamlType(Type type) - { - XamlType result = null; - - if (_cachedTypes.TryGetValue(type, out result)) - { - return result; - } - - _cachedTypes[type] = result = GetAvaloniaXamlType(type) ?? base.GetXamlType(type); - - return result; - } - - private static readonly Dictionary _wellKnownExtensionTypes = new Dictionary() - { - { typeof(Binding), typeof(BindingExtension) }, - { typeof(StyleInclude), typeof(StyleIncludeExtension) }, - }; - - private XamlType GetAvaloniaXamlType(Type type) - { - //if type is extension get the original type to check - var origType = _wellKnownExtensionTypes.FirstOrDefault(v => v.Value == type).Key; - - if (typeof(IBinding).GetTypeInfo().IsAssignableFrom((origType ?? type).GetTypeInfo())) - { - return new BindingXamlType(type, this); - } - - if (origType != null || - typeof(AvaloniaObject).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) - { - return new AvaloniaXamlType(type, this); - } - - return null; - } - - protected internal override XamlMember GetAttachableProperty(string attachablePropertyName, MethodInfo getter, MethodInfo setter) - { - var key = MemberKey.Create(getter ?? setter, attachablePropertyName, "a"); - - XamlMember result; - - if (_cachedMembers.TryGetValue(key, out result)) - { - return result; - } - - var type = (getter ?? setter).DeclaringType; - - var prop = AvaloniaPropertyRegistry.Instance.FindRegistered(type, attachablePropertyName); - - if (prop != null) - { - result = new AvaloniaAttachedPropertyXamlMember( - prop, attachablePropertyName, - getter, setter, this); - } - - if (result == null) - { - result = base.GetAttachableProperty(attachablePropertyName, getter, setter); - } - - return _cachedMembers[key] = result; - } - - protected internal override XamlMember GetProperty(PropertyInfo pi) - { - Type objType = pi.DeclaringType; - string name = pi.Name; - - XamlMember result; - - var key = MemberKey.Create(pi, "p"); - - if (_cachedMembers.TryGetValue(key, out result)) - { - return result; - } - - var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(objType, name); - - if (avProp != null) - { - result = new AvaloniaPropertyXamlMember(avProp, pi, this); - } - - if (result == null) - { - result = new PropertyXamlMember(pi, this); - } - - return _cachedMembers[key] = result; - } - - private Dictionary _cachedTypes = new Dictionary(); - - private Dictionary _cachedMembers = new Dictionary(); - - private struct MemberKey - { - public static MemberKey Create(MemberInfo m, string name, string memberType) - { - return new MemberKey(m.DeclaringType, name, memberType); - } - - public static MemberKey Create(MemberInfo m, string memberType) - { - return Create(m, m.Name, memberType); - } - - public MemberKey(Type type, object member, string memberType) - { - Type = type; - Member = member; - MemberType = memberType; - } - - public Type Type { get; } - - public object Member { get; } - - public string MemberType { get; } - - public override string ToString() - { - return $"{MemberType}:{Type.Namespace}:{Type.Name}.{Member}"; - } - } - - - public override bool TryGetCompatibleXamlNamespace(string xamlNamespace, out string compatibleNamespace) - { - //Forces XamlXmlReader to not ignore our namespace in design mode if mc:Ignorable is set - if (IsDesignMode && - xamlNamespace == "http://schemas.microsoft.com/expression/blend/2008") - { - compatibleNamespace = xamlNamespace; - return true; - } - - return base.TryGetCompatibleXamlNamespace(xamlNamespace, out compatibleNamespace); - } - - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs deleted file mode 100644 index 10cf716912..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs +++ /dev/null @@ -1,388 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Data; -using Avalonia.Markup.Data; -using Avalonia.Metadata; -using Avalonia.Styling; -using Portable.Xaml; -using Portable.Xaml.Schema; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Reflection; -using System.Xml.Serialization; - -namespace Avalonia.Markup.Xaml.PortableXaml -{ - using Converters; - using PropertyKey = Tuple; - - public class AvaloniaXamlType : XamlType - { - static readonly AvaloniaPropertyTypeConverter propertyTypeConverter = new AvaloniaPropertyTypeConverter(); - - public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) : - base(underlyingType, schemaContext) - { - } - - protected override XamlMember LookupAttachableMember(string name) - { - var m = base.LookupAttachableMember(name); - - if (m == null) - { - // Might be an AddOwnered attached property. - var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(UnderlyingType, name); - - if (avProp?.IsAttached == true) - { - return new AvaloniaPropertyXamlMember(avProp, this); - } - } - - return m; - } - - protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck) - { - var m = base.LookupMember(name, skipReadOnlyCheck); - - if (m == null && !name.Contains(".")) - { - //so far Portable.xaml haven't found the member/property - //but what if we have AvaloniaProperty - //without setter and/or without getter - //let's try to find the AvaloniaProperty as a fallback - var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(UnderlyingType, name); - - if (avProp != null && !(skipReadOnlyCheck && avProp.IsReadOnly)) - { - m = new AvaloniaPropertyXamlMember(avProp, this); - } - } - - return m; - } - } - - public class BindingXamlType : XamlType - { - private static List _notAssignable = - new List - { - typeof (IXmlSerializable) - }; - - public BindingXamlType(Type underlyingType, XamlSchemaContext schemaContext) : - base(underlyingType, schemaContext) - { - } - - public override bool CanAssignTo(XamlType xamlType) - { - return !_notAssignable.Contains(xamlType.UnderlyingType); - } - } - - public class PropertyXamlMember : XamlMember - { - public PropertyXamlMember(PropertyInfo propertyInfo, XamlSchemaContext schemaContext) - : base(propertyInfo, schemaContext) - { - } - - protected PropertyXamlMember(string attachablePropertyName, - MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext) - : base(attachablePropertyName, getter, setter, schemaContext) - { - } - - protected PropertyXamlMember(string name, XamlType declaringType, bool isAttachable) - : base(name, declaringType, isAttachable) - { - } - - private bool IsReadOnlyCollectionProperty - { - get - { - //Collection properties like: - //MultiBinding.Bindings, Panel.Children, Control.Styles, - //need to be readonly for Portable.Xaml - //Collection properties like: - //Grid.RowDefinitions, Grid.ColumnDefinitions - //need to be set only once, and subsequent changes to be - //added to collection - //TODO: investigate is this good enough as solution ??? - //We can add some ReadOnyXamlPropertyCollectionAttribute to cover this - return Type.IsCollection; - } - } - - private bool HasCollectionTypeConverter - { - get - { - return Type.IsCollection && Type.TypeConverter != null; - } - } - - protected override MethodInfo LookupUnderlyingSetter() - { - //if we have content property a list - //we have some issues in portable.xaml - //but if the list is read only, this is solving the problem - - if (IsReadOnlyCollectionProperty && - !HasCollectionTypeConverter) - { - return null; - } - - return base.LookupUnderlyingSetter(); - } - - protected override XamlMemberInvoker LookupInvoker() - { - //if we have a IList property and it has TypeConverter - //Portable.xaml need to be able to set the value - //but instead directly set new value we'll sync the lists - bool updateListInsteadSet = HasCollectionTypeConverter; - return new PropertyInvoker(this) - { - UpdateListInsteadSet = updateListInsteadSet - }; - } - - protected override bool LookupIsUnknown() => false; - - protected override XamlType LookupType() - { - var propType = GetPropertyType(); - - if (propType != null) - { - if (propType == typeof(IEnumerable)) - { - //TODO: Portable.xaml is not handling well IEnumerable - //let's threat IEnumerable property as list - //revisit this when smarter solution is found - propType = typeof(IList); - } - - return DeclaringType.SchemaContext.GetXamlType(propType); - } - - return base.LookupType(); - } - - protected virtual Type GetPropertyType() - { - return (UnderlyingMember as PropertyInfo)?.PropertyType; - } - - private IList _dependsOn; - - protected override IList LookupDependsOn() - { - if (_dependsOn == null) - { - var attrib = UnderlyingMember.GetCustomAttribute(true); - - if (attrib != null) - { - var member = DeclaringType.GetMember(attrib.Name); - - _dependsOn = new XamlMember[] { member }; - } - else - { - _dependsOn = base.LookupDependsOn(); - } - } - - return _dependsOn; - } - - private PropertyKey PropertyKey() - => new PropertyKey(DeclaringType.UnderlyingType, Name); - - private class PropertyInvoker : XamlMemberInvoker - { - public bool UpdateListInsteadSet { get; set; } = false; - - public PropertyInvoker(XamlMember member) : base(member) - { - } - - public override void SetValue(object instance, object value) - { - //can't make it work to assign TypeConverter to Setter.Value - //so we need it hard coded - //TODO: try to assosiate TypeConverter with Setter.Value - //and remove this lines - if (instance is Setter && - Member.Name == nameof(Setter.Value) && - value is string) - { - value = SetterValueTypeConverter.ConvertSetterValue(null, - Member.DeclaringType.SchemaContext, CultureInfo.InvariantCulture, - instance as Setter, - value); - } - - if (UpdateListInsteadSet && - value != null && - UpdateListInsteadSetValue(instance, value)) - { - return; - } - - base.SetValue(instance, value); - } - - private bool UpdateListInsteadSetValue(object instance, object value) - { - object old = GetValue(instance); - - if (Equals(old, value)) - { - //don't set the same collection value - return true; - } - else if (old is IList && value is IList) - { - var oldList = (IList)old; - var curList = (IList)value; - - oldList.Clear(); - - foreach (object item in curList) - { - oldList.Add(item); - } - - return true; - } - - return false; - } - } - } - - public class AvaloniaPropertyXamlMember : PropertyXamlMember - { - private bool? _assignBinding; - - public bool AssignBinding => (bool)(_assignBinding ?? (_assignBinding = UnderlyingMember?.GetCustomAttribute() != null)); - - public AvaloniaProperty Property { get; } - - public AvaloniaPropertyXamlMember(AvaloniaProperty property, - PropertyInfo propertyInfo, - XamlSchemaContext schemaContext) : - base(propertyInfo, schemaContext) - { - Property = property; - } - - public AvaloniaPropertyXamlMember(AvaloniaProperty property, XamlType type) : - base(property.Name, type, false) - { - Property = property; - } - - protected AvaloniaPropertyXamlMember(AvaloniaProperty property, - string attachablePropertyName, - MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext) - : base(attachablePropertyName, getter, setter, schemaContext) - { - Property = property; - } - - protected override XamlMemberInvoker LookupInvoker() - { - return new AvaloniaPropertyInvoker(this); - } - - protected override bool LookupIsReadOnly() - { - return Property.IsReadOnly; - } - - protected override Type GetPropertyType() - { - return Property.PropertyType; - } - - private class AvaloniaPropertyInvoker : XamlMemberInvoker - { - public AvaloniaPropertyInvoker(XamlMember member) : base(member) - { - } - - public override void SetValue(object instance, object value) - { - if (Property != null) - { - var obj = ((IAvaloniaObject)instance); - if (value is IBinding) - { - if (!Member.AssignBinding) - ApplyBinding(obj, (IBinding)value); - else - obj.SetValue(Property, value); - } - else - { - obj.SetValue(Property, value); - } - } - else - { - base.SetValue(instance, value); - } - } - - public override object GetValue(object instance) - { - if (Property != null && !Property.IsAttached) - { - return ((IAvaloniaObject)instance).GetValue(Property); - } - else - { - return base.GetValue(instance); - } - } - - private void ApplyBinding(IAvaloniaObject obj, IBinding binding) - { - var control = obj as IControl; - var property = Property; - - if (control != null && property != Control.DataContextProperty) - DelayedBinding.Add(control, property, binding); - else - obj.Bind(property, binding); - } - - private AvaloniaProperty Property => Member.Property; - - private new AvaloniaPropertyXamlMember Member => - (AvaloniaPropertyXamlMember)base.Member; - } - } - - public class AvaloniaAttachedPropertyXamlMember : AvaloniaPropertyXamlMember - { - public AvaloniaAttachedPropertyXamlMember(AvaloniaProperty property, - string attachablePropertyName, - MethodInfo getter, MethodInfo setter, - XamlSchemaContext schemaContext) - : base(property, attachablePropertyName, getter, setter, schemaContext) - { - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs deleted file mode 100644 index a48f400af2..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Avalonia.Markup.Xaml.PortableXaml; -using Portable.Xaml.Markup; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.ComponentModel; - -namespace Portable.Xaml.ComponentModel -{ - internal static class TypeDescriptorExtensions - { - /// - /// Gets the service from ITypeDescriptorContext - /// usually in TypeConverter in xaml reader context - /// examples: - /// context.GetService<IXamlTypeResolver>() - /// context.GetService<IXamlNamespaceResolver>() - /// context.GetService<IXamlNameProvider>() - /// context.GetService<INamespacePrefixLookup>() - /// context.GetService<IXamlSchemaContextProvider>() - /// context.GetService<IRootObjectProvider>() - /// context.GetService<IProvideValueTarget>() - /// - /// Service Type - /// The TypeDescriptor context. - /// - public static T GetService(this ITypeDescriptorContext ctx) where T : class - { - return ctx.GetService(typeof(T)) as T; - } - - public static Type ResolveType(this ITypeDescriptorContext ctx, string namespacePrefix, string type) - { - var tr = ctx.GetService(); - - string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}"; - - return tr?.Resolve(name); - } - - public static T GetFirstAmbientValue(this ITypeDescriptorContext ctx) where T : class - { - var amb = ctx.GetService(); - var sc = ctx.GetService().SchemaContext; - - // Because GetFirstParent uses XamlType.CanAssignTo it returns values that - // aren't actually of the correct type. Use GetAllAmbientValues instead. - return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType().FirstOrDefault(); - } - - public static T GetLastOrDefaultAmbientValue(this ITypeDescriptorContext ctx) where T : class - { - return ctx.GetAllAmbientValues().LastOrDefault() as T; - } - - public static IEnumerable GetAllAmbientValues(this ITypeDescriptorContext ctx) where T : class - { - var amb = ctx.GetService(); - var sc = ctx.GetService().SchemaContext; - - return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType(); - } - - public static Uri GetBaseUri(this ITypeDescriptorContext ctx) - { - return ctx.GetWriterSettings()?.Context?.BaseUri; - } - - public static Assembly GetLocalAssembly(this ITypeDescriptorContext ctx) - { - return ctx.GetWriterSettings()?.Context?.LocalAssembly; - } - - public static AvaloniaXamlContext GetAvaloniaXamlContext(this ITypeDescriptorContext ctx) - { - return ctx.GetWriterSettings()?.Context; - } - - public static XamlObjectWriterSettings WithContext(this XamlObjectWriterSettings settings, AvaloniaXamlContext context) - { - return new AvaloniaXamlObjectWriterSettings(settings, context); - } - - private static AvaloniaXamlObjectWriterSettings GetWriterSettings(this ITypeDescriptorContext ctx) - { - return ctx.GetService().GetParentSettings() as AvaloniaXamlObjectWriterSettings; - } - - private class AvaloniaXamlObjectWriterSettings : XamlObjectWriterSettings - { - public AvaloniaXamlObjectWriterSettings(XamlObjectWriterSettings settings, AvaloniaXamlContext context) - : base(settings) - { - Context = context; - } - - public AvaloniaXamlContext Context { get; } - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github deleted file mode 160000 index ab55261737..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ab5526173722b8988bc5ca3c03c8752ce89c0975 diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs index ff367c0e13..ead373d380 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs @@ -7,42 +7,16 @@ using System.Collections.Generic; namespace Avalonia.Markup.Xaml.Templates { - using Portable.Xaml; - - public class TemplateContent + + public static class TemplateContent { - public TemplateContent(IEnumerable namespaces, XamlReader reader, - IAmbientProvider ambientProvider) - { - ParentAmbientProvider = ambientProvider; - List = new XamlNodeList(reader.SchemaContext); - - //we need to rpeserve all namespace and prefixes to writer - //otherwise they are lost. a bug in Portable.xaml or by design ?? - foreach (var ns in namespaces) - { - List.Writer.WriteNamespace(ns); - } - - XamlServices.Transform(reader, List.Writer); - } - - public XamlNodeList List { get; } - - private IAmbientProvider ParentAmbientProvider { get; } - - public IControl Load() - { - return (IControl)AvaloniaXamlLoader.LoadFromReader(List.GetReader(), parentAmbientProvider: ParentAmbientProvider); - } - public static IControl Load(object templateContent) { if (templateContent is Func direct) { return (IControl)direct(null); } - return ((TemplateContent)templateContent).Load(); + throw new ArgumentException(nameof(templateContent)); } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs deleted file mode 100644 index e29485ddb0..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Avalonia.Markup.Xaml.Templates -{ - using Portable.Xaml; - using Portable.Xaml.ComponentModel; - using System.ComponentModel; - using System; - - public class TemplateLoader : XamlDeferringLoader - { - public override object Load(XamlReader xamlReader, IServiceProvider serviceProvider) - { - var tdc = (ITypeDescriptorContext)serviceProvider; - var ns = tdc.GetService(); - var ambientProvider = tdc.GetService(); - return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader, ambientProvider); - } - - public override XamlReader Save(object value, IServiceProvider serviceProvider) - { - return ((TemplateContent)value).List.GetReader(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 581dbcdac7..c25e1186d0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -28,15 +28,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions XmlnsAttributes = { typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"), - typeSystem.FindType("Portable.Xaml.Markup.XmlnsDefinitionAttribute") }, ContentAttributes = { typeSystem.GetType("Avalonia.Metadata.ContentAttribute") }, - ProvideValueTarget = typeSystem.GetType("Portable.Xaml.Markup.IProvideValueTarget"), - RootObjectProvider = typeSystem.GetType("Portable.Xaml.IRootObjectProvider"), - UriContextProvider = typeSystem.GetType("Portable.Xaml.Markup.IUriContext"), + ProvideValueTarget = typeSystem.GetType("Avalonia.Markup.Xaml.IProvideValueTarget"), + RootObjectProvider = typeSystem.GetType("Avalonia.Markup.Xaml.IRootObjectProvider"), + UriContextProvider = typeSystem.GetType("Avalonia.Markup.Xaml.IUriContext"), ParentStackProvider = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlParentStackProvider"), @@ -47,7 +46,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions runtimeHelpers.FindMethod(m => m.Name == "DeferredTransformationFactoryV1"), UsableDuringInitializationAttributes = { - typeSystem.GetType("Portable.Xaml.Markup.UsableDuringInitializationAttribute"), typeSystem.GetType("Avalonia.Metadata.UsableDuringInitializationAttribute"), }, InnerServiceProviderFactoryMethod = @@ -79,15 +77,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions void Add(string type, string conv) => AddType(typeSystem.GetType(type), typeSystem.GetType(conv)); - - //Add("Avalonia.AvaloniaProperty","Avalonia.Markup.Xaml.Converters.AvaloniaPropertyTypeConverter"); Add("Avalonia.Media.Imaging.IBitmap","Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"); var ilist = typeSystem.GetType("System.Collections.Generic.IList`1"); AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter")); Add("Avalonia.Controls.Templates.IMemberSelector", "Avalonia.Markup.Xaml.Converters.MemberSelectorTypeConverter"); - Add("Avalonia.Styling.Selector","Avalonia.Markup.Xaml.Converters.SelectorTypeConverter"); Add("Avalonia.Controls.WindowIcon","Avalonia.Markup.Xaml.Converters.IconTypeConverter"); Add("System.Globalization.CultureInfo", "System.ComponentModel.CultureInfoConverter"); Add("System.Uri", "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter"); diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs index 70b7fe6aec..2d8ea643ac 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs @@ -4,8 +4,6 @@ using System.Linq; using System.Reflection; using Avalonia.Controls; using Avalonia.Data; -using Portable.Xaml; -using Portable.Xaml.Markup; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedParameter.Global diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs new file mode 100644 index 0000000000..06cc85101a --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs @@ -0,0 +1,34 @@ +using System; + +namespace Avalonia.Markup.Xaml +{ + public interface IProvideValueTarget + { + object TargetObject { get; } + object TargetProperty { get; } + } + + public interface IRootObjectProvider + { + object RootObject { get; } + } + + public interface IUriContext + { + Uri BaseUri { get; set; } + } + + public interface IXamlTypeResolver + { + Type Resolve (string qualifiedTypeName); + } + + + public class ConstructorArgumentAttribute : Attribute + { + public ConstructorArgumentAttribute(string name) + { + + } + } +} diff --git a/tests/Avalonia.DesignerSupport.TestApp/App.xaml b/tests/Avalonia.DesignerSupport.TestApp/App.xaml index 214bcd8797..56c0e8059a 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/App.xaml +++ b/tests/Avalonia.DesignerSupport.TestApp/App.xaml @@ -1,6 +1,8 @@ - + - \ No newline at end of file + diff --git a/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj b/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj index ebe64b89ce..6bba5e7348 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj +++ b/tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj @@ -31,6 +31,6 @@ - + diff --git a/tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml b/tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml index 6938bd8c49..f90e5beaa6 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml +++ b/tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml @@ -1,5 +1,7 @@  + Title="TESTAPP" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + x:Class="Avalonia.DesignerSupport.TestApp.MainWindow">