Browse Source

Merge branch 'master' into SelectionBrushFeature

pull/2654/head
Abdulbaqi Alshareef 7 years ago
committed by GitHub
parent
commit
1f611e60c0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitmodules
  2. 3
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  3. 11
      src/Avalonia.Build.Tasks/Program.cs
  4. 4
      src/Avalonia.Controls/ColumnDefinitions.cs
  5. 323
      src/Avalonia.Controls/DefinitionBase.cs
  6. 7
      src/Avalonia.Controls/DefinitionList.cs
  7. 953
      src/Avalonia.Controls/Grid.cs
  8. 32
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  9. 4
      src/Avalonia.Controls/RowDefinitions.cs
  10. 9
      src/Avalonia.Controls/TextBox.cs
  11. 6
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  12. 3
      src/Avalonia.Themes.Default/TextBox.xaml
  13. 21
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  14. 107
      src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
  15. 159
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  16. 99
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs
  17. 1
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
  18. 3
      src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs
  19. 1
      src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs
  20. 1
      src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs
  21. 89
      src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs
  22. 79
      src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs
  23. 27
      src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs
  24. 49
      src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs
  25. 41
      src/Markup/Avalonia.Markup.Xaml/Extensions.cs
  26. 9
      src/Markup/Avalonia.Markup.Xaml/MarkupExtension.cs
  27. 14
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  28. 9
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
  29. 7
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs
  30. 12
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs
  31. 22
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  32. 9
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs
  33. 39
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs
  34. 83
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs
  35. 56
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs
  36. 147
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs
  37. 117
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
  38. 31
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs
  39. 222
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs
  40. 327
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
  41. 388
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
  42. 101
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
  43. 1
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github
  44. 32
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  45. 26
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs
  46. 11
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  47. 7
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  48. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  49. 61
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  50. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  51. 34
      src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
  52. 6
      tests/Avalonia.DesignerSupport.TestApp/App.xaml
  53. 2
      tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj
  54. 6
      tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml
  55. 17
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs
  56. 26
      tests/Avalonia.Markup.Xaml.UnitTests/Converters/AvaloniaPropertyConverterTest.cs
  57. 70
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  58. 14
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/EventTests.cs
  59. 4
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
  60. 42
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
  61. 3
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlTestHelpers.cs

3
.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

3
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -26,9 +26,10 @@
<TextBox Width="200" Text="Left aligned text" TextAlignment="Left" />
<TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
<TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />
<TextBox Width="200" Text="Custom selection brush"
<TextBox Width="200" Text="Custom selection brush"
SelectionStart="5" SelectionEnd="22"
SelectionBrush="Green" SelectionForegroundBrush="Yellow"/>
<TextBox Width="200" Text="Custom caret brush" CaretBrush="DarkOrange"/>
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="8">

11
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()

4
src/Avalonia.Controls/ColumnDefinitions.cs

@ -16,10 +16,8 @@ namespace Avalonia.Controls
/// <summary>
/// Initializes a new instance of the <see cref="ColumnDefinitions"/> class.
/// </summary>
public ColumnDefinitions()
public ColumnDefinitions() : base ()
{
ResetBehavior = ResetBehavior.Remove;
CollectionChanged += OnCollectionChanged;
}
/// <summary>

323
src/Avalonia.Controls/DefinitionBase.cs

@ -20,49 +20,15 @@ namespace Avalonia.Controls
/// </summary>
public abstract class DefinitionBase : AvaloniaObject
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
/* internal DefinitionBase(bool isColumnDefinition)
{
_isColumnDefinition = isColumnDefinition;
_parentIndex = -1;
}*/
#endregion Constructors
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
#region Public Properties
/// <summary>
/// SharedSizeGroup property.
/// </summary>
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
/// <summary>
/// Callback to notify about entering model tree.
/// </summary>
@ -86,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);
}
/// <summary>
/// Callback to notify about exitting model tree.
/// </summary>
@ -139,119 +96,14 @@ namespace Avalonia.Controls
_minSize = minSize;
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal void OnUserSizePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
if (InParentLogicalTree)
{
if (_sharedState != null)
{
_sharedState.Invalidate();
}
else
{
if (((GridLength)e.OldValue).GridUnitType != ((GridLength)e.NewValue).GridUnitType)
{
Parent.Invalidate();
}
else
{
Parent.InvalidateMeasure();
}
}
}
}
/// <summary>
/// <see cref="AvaloniaProperty.ValidateValueCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal static bool IsUserSizePropertyValueValid(object value)
{
return (((GridLength)value).Value >= 0);
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal static void OnUserMinSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
DefinitionBase definition = (DefinitionBase) d;
if (definition.InParentLogicalTree)
{
Grid parentGrid = (Grid) definition.Parent;
parentGrid.InvalidateMeasure();
}
}
/// <summary>
/// <see cref="AvaloniaProperty.ValidateValueCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal static bool IsUserMinSizePropertyValueValid(object value)
{
double v = (double)value;
return (!double.IsNaN(v) && v >= 0.0d && !Double.IsPositiveInfinity(v));
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal static void OnUserMaxSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
DefinitionBase definition = (DefinitionBase) d;
if (definition.InParentLogicalTree)
{
Grid parentGrid = (Grid) definition.Parent;
parentGrid.InvalidateMeasure();
}
}
/// <summary>
/// <see cref="AvaloniaProperty.ValidateValueCallback"/>
/// </summary>
/// <remarks>
/// This method needs to be internal to be accessable from derived classes.
/// </remarks>
internal static bool IsUserMaxSizePropertyValueValid(object value)
{
double v = (double)value;
return (!double.IsNaN(v) && v >= 0.0d);
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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 +114,6 @@ namespace Avalonia.Controls
}
}
#endregion Internal Methods
//------------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
/// <summary>
/// Returns <c>true</c> if this definition is a part of shared group.
/// </summary>
@ -349,8 +191,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 +217,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 +235,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,27 +268,9 @@ namespace Avalonia.Controls
/// Internal helper to access up-to-date UserMaxSize property value.
/// </summary>
internal abstract double UserMaxSizeValueCache { get; }
/// <summary>
/// Protected. Returns <c>true</c> if this DefinitionBase instance is in parent's logical tree.
/// </summary>
internal bool InParentLogicalTree
{
get { return (_parentIndex != -1); }
}
internal Grid Parent { get; set; }
#endregion Internal Properties
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
/// <summary>
/// SetFlags is used to set or unset one or multiple
/// flags on the object.
@ -465,16 +289,13 @@ namespace Avalonia.Controls
return ((_flags & flags) == flags);
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
private static void OnSharedSizeGroupPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
DefinitionBase definition = (DefinitionBase) d;
if (definition.InParentLogicalTree)
DefinitionBase definition = (DefinitionBase)d;
if (definition.Parent != null)
{
string sharedSizeGroupId = (string) e.NewValue;
string sharedSizeGroupId = (string)e.NewValue;
if (definition._sharedState != null)
{
@ -483,7 +304,7 @@ namespace Avalonia.Controls
definition._sharedState.RemoveMember(definition);
definition._sharedState = null;
}
if ((definition._sharedState == null) && (sharedSizeGroupId != null))
{
SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope;
@ -498,9 +319,6 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// <see cref="AvaloniaProperty.ValidateValueCallback"/>
/// </summary>
/// <remarks>
/// Verifies that Shared Size Group Property string
/// a) not empty.
@ -520,10 +338,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 +353,9 @@ namespace Avalonia.Controls
}
}
throw new ArgumentException("Invalid SharedSizeGroup string.");
throw new ArgumentException("Invalid SharedSizeGroup string.");
}
/// <summary>
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
/// </summary>
/// <remark>
/// OnPrivateSharedSizeScopePropertyChanged is called when new scope enters or
/// existing scope just left. In both cases if the DefinitionBase object is already registered
@ -550,9 +365,9 @@ namespace Avalonia.Controls
{
DefinitionBase definition = (DefinitionBase)d;
if (definition.InParentLogicalTree)
if (definition.Parent != null)
{
SharedSizeScope privateSharedSizeScope = (SharedSizeScope) e.NewValue;
SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue;
if (definition._sharedState != null)
{
@ -576,22 +391,12 @@ namespace Avalonia.Controls
}
}
#endregion Private Methods
//------------------------------------------------------
//
// Private Properties
//
//------------------------------------------------------
#region Private Properties
/// <summary>
/// Private getter of shared state collection dynamic property.
/// </summary>
private SharedSizeScope PrivateSharedSizeScope
{
get { return (SharedSizeScope) GetValue(PrivateSharedSizeScopeProperty); }
get { return (SharedSizeScope)GetValue(PrivateSharedSizeScopeProperty); }
}
/// <summary>
@ -612,16 +417,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 +428,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 +435,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
}
/// <summary>
@ -799,8 +581,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 +627,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 +639,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 +661,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<DefinitionBase> _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<DefinitionBase> _registry;
//------------------------------------------------------
//
// Properties
//
//------------------------------------------------------
// Instance event handler for layout updated event
private readonly EventHandler _layoutUpdated;
#region Properties
// Control for which layout updated event handler is registered
private Control _layoutUpdatedHost;
// "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;
}
/// <summary>
/// Private shared size scope property holds a collection of shared state objects for the a given shared size scope.
@ -931,7 +720,7 @@ namespace Avalonia.Controls
public static readonly AttachedProperty<string> SharedSizeGroupProperty =
AvaloniaProperty.RegisterAttached<DefinitionBase, Control, string>(
"SharedSizeGroup",
validate:SharedSizeGroupPropertyValueValid);
validate: SharedSizeGroupPropertyValueValid);
/// <summary>
/// Static ctor. Used for static registration of properties.
@ -941,7 +730,5 @@ namespace Avalonia.Controls
SharedSizeGroupProperty.Changed.AddClassHandler<DefinitionBase>(OnSharedSizeGroupPropertyChanged);
PrivateSharedSizeScopeProperty.Changed.AddClassHandler<DefinitionBase>(OnPrivateSharedSizeScopePropertyChanged);
}
#endregion Properties
}
}

7
src/Avalonia.Controls/DefinitionList.cs

@ -10,6 +10,12 @@ namespace Avalonia.Controls
{
public abstract class DefinitionList<T> : AvaloniaList<T> 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;

953
src/Avalonia.Controls/Grid.cs

File diff suppressed because it is too large

32
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -25,6 +25,9 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty<IBrush> SelectionForegroundBrushProperty =
AvaloniaProperty.Register<TextPresenter, IBrush>(nameof(SelectionForegroundBrushProperty));
public static readonly StyledProperty<IBrush> CaretBrushProperty =
AvaloniaProperty.Register<TextPresenter, IBrush>(nameof(CaretBrushProperty));
public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
o => o.SelectionStart,
@ -40,7 +43,7 @@ namespace Avalonia.Controls.Presenters
private int _selectionStart;
private int _selectionEnd;
private bool _caretBlink;
static TextPresenter()
{
AffectsRender<TextPresenter>(PasswordCharProperty);
@ -95,6 +98,12 @@ namespace Avalonia.Controls.Presenters
get => GetValue(SelectionForegroundBrushProperty);
set => SetValue(SelectionForegroundBrushProperty, value);
}
public IBrush CaretBrush
{
get => GetValue(CaretBrushProperty);
set => SetValue(CaretBrushProperty, value);
}
public int SelectionStart
{
@ -156,16 +165,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)

4
src/Avalonia.Controls/RowDefinitions.cs

@ -14,10 +14,8 @@ namespace Avalonia.Controls
/// <summary>
/// Initializes a new instance of the <see cref="RowDefinitions"/> class.
/// </summary>
public RowDefinitions()
public RowDefinitions() : base()
{
ResetBehavior = ResetBehavior.Remove;
CollectionChanged += OnCollectionChanged;
}
/// <summary>

9
src/Avalonia.Controls/TextBox.cs

@ -44,6 +44,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush> SelectionForegroundBrushProperty =
AvaloniaProperty.Register<TextBox, IBrush>(nameof(SelectionForegroundBrushProperty));
public static readonly StyledProperty<IBrush> CaretBrushProperty =
AvaloniaProperty.Register<TextBox, IBrush>(nameof(CaretBrushProperty));
public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
AvaloniaProperty.RegisterDirect<TextBox, int>(
nameof(SelectionStart),
@ -187,6 +190,12 @@ namespace Avalonia.Controls
set => SetValue(SelectionForegroundBrushProperty, value);
}
public IBrush CaretBrush
{
get => GetValue(CaretBrushProperty);
set => SetValue(CaretBrushProperty, value);
}
public int SelectionStart
{
get

6
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,
}
});
}

3
src/Avalonia.Themes.Default/TextBox.xaml

@ -48,7 +48,8 @@
TextWrapping="{TemplateBinding TextWrapping}"
PasswordChar="{TemplateBinding PasswordChar}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"/>
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
CaretBrush="{TemplateBinding CaretBrush}"/>
</Panel>
</ScrollViewer>
</DataValidationErrors>

21
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -11,38 +11,22 @@
<ItemGroup>
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\AvaloniaUriTypeConverter.cs" />
<Compile Include="Converters\AvaloniaEventConverter.cs" />
<Compile Include="Converters\FontFamilyTypeConverter.cs" />
<Compile Include="Converters\MemberSelectorTypeConverter.cs" />
<Compile Include="Converters\NullableTypeConverter.cs" />
<Compile Include="Converters\ParseTypeConverter.cs" />
<Compile Include="Converters\SetterValueTypeConverter.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="MarkupExtension.cs" />
<Compile Include="MarkupExtensions\DynamicResourceExtension.cs" />
<Compile Include="MarkupExtensions\ResourceInclude.cs" />
<Compile Include="MarkupExtensions\StaticResourceExtension.cs" />
<Compile Include="MarkupExtensions\StyleIncludeExtension.cs" />
<Compile Include="Parsers\PropertyParser.cs" />
<Compile Include="PortableXaml\AvaloniaResourceXamlInfo.cs" />
<Compile Include="PortableXaml\AvaloniaXamlContext.cs" />
<Compile Include="PortableXaml\AttributeExtensions.cs" />
<Compile Include="PortableXaml\AvaloniaMemberAttributeProvider.cs" />
<Compile Include="PortableXaml\AvaloniaNameScope.cs" />
<Compile Include="AvaloniaTypeConverters.cs" />
<Compile Include="PortableXaml\AvaloniaXamlObjectWriter.cs" />
<Compile Include="PortableXaml\AvaloniaRuntimeTypeProvider.cs" />
<Compile Include="PortableXaml\AvaloniaXamlSchemaContext.cs" />
<Compile Include="Converters\BitmapTypeConverter.cs" />
<Compile Include="Converters\IconTypeConverter.cs" />
<Compile Include="Converters\AvaloniaPropertyTypeConverter.cs" />
<Compile Include="Converters\PointsListTypeConverter.cs" />
<Compile Include="Converters\SelectorTypeConverter.cs" />
<Compile Include="MarkupExtensions\BindingExtension.cs" />
<Compile Include="MarkupExtensions\RelativeSourceExtension.cs" />
<Compile Include="PortableXaml\AvaloniaTypeAttributeProvider.cs" />
<Compile Include="PortableXaml\AvaloniaXamlType.cs" />
<Compile Include="PortableXaml\TypeDescriptorExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Styling\StyleInclude.cs" />
<Compile Include="Templates\ControlTemplate.cs" />
@ -52,7 +36,6 @@
<Compile Include="Templates\MemberSelector.cs" />
<Compile Include="Templates\Template.cs" />
<Compile Include="Templates\TemplateContent.cs" />
<Compile Include="Templates\TemplateLoader.cs" />
<Compile Include="Templates\TreeDataTemplate.cs" />
<Compile Include="XamlIl\AvaloniaXamlIlRuntimeCompiler.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaBindingExtensionHackTransformer.cs" />
@ -76,11 +59,11 @@
<Compile Include="XamlIl\Runtime\IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs" />
<Compile Include="XamlIl\Runtime\XamlIlRuntimeHelpers.cs" />
<Compile Include="XamlLoadException.cs" />
<Compile Include="PortableXaml\portable.xaml.github\src\Portable.Xaml\**\*.cs" Exclude="PortableXaml\portable.xaml.github\src\Portable.Xaml\Assembly\**\*.cs" />
<Compile Include="XamlIl\xamlil.github\src\XamlIl\**\*.cs" />
<Compile Condition="$(UseCecil) == true" Include="XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs" />
<Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" />
<Compile Include="..\Avalonia.Markup\Markup\Parsers\SelectorGrammar.cs" />
<Compile Include="XamlTypes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />

107
src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs

@ -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;
/// <summary>
/// Maintains a repository of <see cref="TypeConverter"/>s for XAML parsing on top of those
/// maintained by <see cref="TypeDescriptor"/>.
/// </summary>
/// <remarks>
/// The default method of defining type converters using <see cref="TypeConverterAttribute"/>
/// isn't powerful enough for our purposes:
///
/// - It doesn't handle non-constructed generic types (such as <see cref="AvaloniaList{T}"/>)
/// - Type converters which require XAML features cannot be defined in non-XAML assemblies and
/// so can't be referenced using <see cref="TypeConverterAttribute"/>
/// - Many types have a static `Parse(string)` method which can be used implicitly; this class
/// detects such methods and auto-creates a type converter
/// </remarks>
public static class AvaloniaTypeConverters
{
// When adding item to that list make sure to modify AvaloniaXamlIlLanguage
private static Dictionary<Type, Type> _converters = new Dictionary<Type, Type>()
{
{ typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) },
{ typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) },
{ typeof(IBitmap), typeof(BitmapTypeConverter) },
{ typeof(IList<Point>), 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;
}
/// <summary>
/// Tries to lookup a <see cref="TypeConverter"/> for a type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The type converter.</returns>
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;
}
/// <summary>
/// Registers a type converter for a type.
/// </summary>
/// <param name="type">The type. Maybe be a non-constructed generic type.</param>
/// <param name="converterType">The converter type. Maybe be a non-constructed generic type.</param>
public static void Register(Type type, Type converterType) => _converters[type] = converterType;
}
}

159
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;
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
/// </summary>
public AvaloniaXamlLoader()
{
}
/// <summary>
/// Loads the XAML into a Avalonia component.
/// </summary>
/// <param name="obj">The object to load the XAML into.</param>
public static void Load(object obj)
{
Contract.Requires<ArgumentNullException>(obj != null);
var loader = new AvaloniaXamlLoader();
loader.Load(obj.GetType(), obj);
}
/// <summary>
/// Loads the XAML for a type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="rootInstance">
/// The optional instance into which the XAML should be loaded.
/// </param>
/// <returns>The loaded object.</returns>
public object Load(Type type, object rootInstance = null)
{
Contract.Requires<ArgumentNullException>(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<IAssetLoader>();
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");
}
/// <summary>
@ -100,11 +42,8 @@ namespace Avalonia.Markup.Xaml
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <param name="rootInstance">
/// The optional instance into which the XAML should be loaded.
/// </param>
/// <returns>The loaded object.</returns>
public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
public object Load(Uri uri, Uri baseUri = null)
{
Contract.Requires<ArgumentNullException>(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
/// </param>
/// <param name="uri">The URI of the XAML</param>
/// <returns>The loaded object.</returns>
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));
/// <summary>
/// Gets the URI for a type.
/// </summary>
/// <param name="assetLocator"></param>
/// <param name="type">The type.</param>
/// <returns>The URI.</returns>
private static IEnumerable<Uri> 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<string,string> 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);

99
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaEventConverter.cs

@ -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);
}
}
}

1
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
{

3
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
{

1
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
{

1
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

89
src/Markup/Avalonia.Markup.Xaml/Converters/NullableTypeConverter.cs

@ -1,89 +0,0 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
public class NullableTypeConverter<T> : 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);
}
}
}

79
src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs

@ -1,79 +0,0 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
namespace Avalonia.Markup.Xaml.Converters
{
/// <summary>
/// Base class for type converters which call a static Parse method.
/// </summary>
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) };
/// <summary>
/// Checks whether a type has a suitable Parse method.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>True if the type has a suitable parse method, otherwise false.</returns>
public static bool HasParseMethod(Type type)
{
return type.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null) != null ||
type.GetMethod("Parse", PublicStatic, null, StringParameter, null) != null;
}
}
/// <summary>
/// A type converter which calls a static Parse method.
/// </summary>
/// <typeparam name="T">The type with the Parse method.</typeparam>
public class ParseTypeConverter<T> : ParseTypeConverter
{
private static Func<string, T> _parse;
private static Func<string, IFormatProvider, T> _parseWithFormat;
static ParseTypeConverter()
{
var method = typeof(T).GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null);
if (method != null)
{
_parseWithFormat = (Func<string, IFormatProvider, T>)method
.CreateDelegate(typeof(Func<string, IFormatProvider, T>));
return;
}
method = typeof(T).GetMethod("Parse", PublicStatic, null, StringParameter, null);
if (method != null)
{
_parse = (Func<string, T>)method.CreateDelegate(typeof(Func<string, T>));
}
}
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;
}
}
}

27
src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs

@ -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);
}
}
}

49
src/Markup/Avalonia.Markup.Xaml/Converters/SetterValueTypeConverter.cs

@ -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<IProvideValueTarget>().TargetObject;
var schemaContext = context.GetService<IXamlSchemaContextProvider>().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;
}
}
}

41
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<T>(this IServiceProvider sp) => (T)sp?.GetService(typeof(T));
public static Uri GetContextBaseUri(this IServiceProvider ctx)
{
var properService = ctx.GetService<IUriContext>();
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<IUriContext>().BaseUri;
public static T GetFirstParent<T>(this IServiceProvider ctx) where T : class
{
var parentStack = ctx.GetService<IAvaloniaXamlIlParentStackProvider>();
if (parentStack != null)
return parentStack.Parents.OfType<T>().FirstOrDefault();
return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetFirstAmbientValue<T>((ITypeDescriptorContext)ctx);
}
public static T GetLastParent<T>(this IServiceProvider ctx) where T : class
{
var parentStack = ctx.GetService<IAvaloniaXamlIlParentStackProvider>();
if (parentStack != null)
return parentStack.Parents.OfType<T>().LastOrDefault();
return Portable.Xaml.ComponentModel.TypeDescriptorExtensions.GetLastOrDefaultAmbientValue<T>(
(ITypeDescriptorContext)ctx);
}
public static T GetFirstParent<T>(this IServiceProvider ctx) where T : class
=> ctx.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>().FirstOrDefault();
public static T GetLastParent<T>(this IServiceProvider ctx) where T : class
=> ctx.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>().LastOrDefault();
public static IEnumerable<T> GetParents<T>(this IServiceProvider sp)
{
var stack = sp.GetService<IAvaloniaXamlIlParentStackProvider>();
if (stack != null)
return stack.Parents.OfType<T>();
return sp.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>();
var context = (ITypeDescriptorContext)sp;
var schemaContext = context.GetService<IXamlSchemaContextProvider>().SchemaContext;
var ambientProvider = context.GetService<IAmbientProvider>();
return ambientProvider.GetAllAmbientValues(schemaContext.GetXamlType(typeof(T))).OfType<T>();
}
public static Type ResolveType(this IServiceProvider ctx, string namespacePrefix, string type)

9
src/Markup/Avalonia.Markup.Xaml/MarkupExtension.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Markup.Xaml
{
public abstract class MarkupExtension
{
public abstract object ProvideValue(IServiceProvider serviceProvider);
}
}

14
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;

9
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<IProvideValueTarget>();

7
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;
}
}
}

12
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
{
/// <summary>
/// Loads a resource dictionary from a specified URL.
/// </summary>
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);
}
/// <inhertidoc/>
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();

22
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<IResourceNode>())
{
// 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;
}

9
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 };
}

39
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs

@ -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);
}
}
}

83
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs

@ -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<avm.TemplateContentAttribute>(inherit)
.ToPortableXaml();
}
else if (attributeType == typeof(pm.AmbientAttribute))
{
result = _info.GetCustomAttribute<avm.AmbientAttribute>(inherit)
.ToPortableXaml();
}
else if (attributeType == typeof(pm.DependsOnAttribute))
{
result = _info.GetCustomAttribute<avm.DependsOnAttribute>(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;
}
}

56
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaNameScope.cs

@ -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<string, object> _names = new Dictionary<string, object>();
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);
}
}
}
}
}

147
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs

@ -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<string, Assembly>;
public interface IRuntimeTypeProvider
{
Type FindType(string xamlNamespace, string name, Type[] genArgs);
IEnumerable<Assembly> ReferencedAssemblies { get; }
}
public class AvaloniaRuntimeTypeProvider : IRuntimeTypeProvider
{
private const string ClrNamespace = "clr-namespace:";
// private const string AvaloniaNs = "https://github.com/avaloniaui";
private static readonly IEnumerable<Assembly> 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<string, HashSet<ClrNamespaceInfo>> _namespaces = new Dictionary<string, HashSet<ClrNamespaceInfo>>();
private List<Assembly> _scanned = new List<Assembly>();
public IEnumerable<Assembly> 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<Assembly> assemblies)
{
foreach (var assembly in assemblies)
{
var namespaces = assembly.GetCustomAttributes<XmlnsDefinitionAttribute>()
.Select(x => new { x.XmlNamespace, x.ClrNamespace })
.GroupBy(x => x.XmlNamespace);
foreach (var nsa in namespaces)
{
HashSet<ClrNamespaceInfo> reg;
if (!_namespaces.TryGetValue(nsa.Key, out reg))
{
_namespaces[nsa.Key] = reg = new HashSet<Tuple<string, Assembly>>();
}
foreach (var child in nsa)
{
reg.Add(new ClrNamespaceInfo(child.ClrNamespace, assembly));
}
}
_scanned.Add(assembly);
}
}
private void ScanNewAssemblies()
{
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies();
if (assemblies != null)
{
assemblies = assemblies.Except(_scanned);
ScanAssemblies(assemblies);
}
}
private Dictionary<string, Type> _typeCache = new Dictionary<string, Type>();
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<ClrNamespaceInfo> 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;
}
}
}

117
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs

@ -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<avm.AmbientAttribute>(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<avm.ContentAttribute>() != 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;
}
}
}

31
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlContext.cs

@ -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
};
}
}
}

222
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs

@ -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<XamlDirective, string> DesignDirectives = new Dictionary<string, string>
{
["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<object> _targets = new HashSet<object>();
private IList<DelayedValue> _values = new List<DelayedValue>();
private IEnumerable<DelayedValue> 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; }
}
}
}
}

327
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs

@ -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<ArgumentNullException>(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<Tuple<string, string>, 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<Tuple<string, string>, 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<string, string>(ns, type.Name), xamlType);
}
}
XamlType result;
var key = new Tuple<string, string>(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<Type, Type> _wellKnownExtensionTypes = new Dictionary<Type, Type>()
{
{ 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<Type, XamlType> _cachedTypes = new Dictionary<Type, XamlType>();
private Dictionary<MemberKey, XamlMember> _cachedMembers = new Dictionary<MemberKey, XamlMember>();
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);
}
}
}

388
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs

@ -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<Type, string>;
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<Type> _notAssignable =
new List<Type>
{
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<XamlMember> _dependsOn;
protected override IList<XamlMember> LookupDependsOn()
{
if (_dependsOn == null)
{
var attrib = UnderlyingMember.GetCustomAttribute<DependsOnAttribute>(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<AssignBindingAttribute>() != 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)
{
}
}
}

101
src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs

@ -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
{
/// <summary>
/// Gets the service from ITypeDescriptorContext
/// usually in TypeConverter in xaml reader context
/// examples:
/// context.GetService&lt;IXamlTypeResolver&gt;()
/// context.GetService&lt;IXamlNamespaceResolver&gt;()
/// context.GetService&lt;IXamlNameProvider&gt;()
/// context.GetService&lt;INamespacePrefixLookup&gt;()
/// context.GetService&lt;IXamlSchemaContextProvider&gt;()
/// context.GetService&lt;IRootObjectProvider&gt;()
/// context.GetService&lt;IProvideValueTarget&gt;()
/// </summary>
/// <typeparam name="T">Service Type</typeparam>
/// <param name="ctx">The TypeDescriptor context.</param>
/// <returns></returns>
public static T GetService<T>(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<IXamlTypeResolver>();
string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}";
return tr?.Resolve(name);
}
public static T GetFirstAmbientValue<T>(this ITypeDescriptorContext ctx) where T : class
{
var amb = ctx.GetService<IAmbientProvider>();
var sc = ctx.GetService<IXamlSchemaContextProvider>().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<T>().FirstOrDefault();
}
public static T GetLastOrDefaultAmbientValue<T>(this ITypeDescriptorContext ctx) where T : class
{
return ctx.GetAllAmbientValues<T>().LastOrDefault() as T;
}
public static IEnumerable<T> GetAllAmbientValues<T>(this ITypeDescriptorContext ctx) where T : class
{
var amb = ctx.GetService<IAmbientProvider>();
var sc = ctx.GetService<IXamlSchemaContextProvider>().SchemaContext;
return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType<T>();
}
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<IXamlObjectWriterFactory>().GetParentSettings() as AvaloniaXamlObjectWriterSettings;
}
private class AvaloniaXamlObjectWriterSettings : XamlObjectWriterSettings
{
public AvaloniaXamlObjectWriterSettings(XamlObjectWriterSettings settings, AvaloniaXamlContext context)
: base(settings)
{
Context = context;
}
public AvaloniaXamlContext Context { get; }
}
}
}

1
src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github

@ -1 +0,0 @@
Subproject commit ab5526173722b8988bc5ca3c03c8752ce89c0975

32
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<NamespaceDeclaration> 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<IServiceProvider, object> direct)
{
return (IControl)direct(null);
}
return ((TemplateContent)templateContent).Load();
throw new ArgumentException(nameof(templateContent));
}
}
}

26
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs

@ -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<IXamlNamespaceResolver>();
var ambientProvider = tdc.GetService<IAmbientProvider>();
return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader, ambientProvider);
}
public override XamlReader Save(object value, IServiceProvider serviceProvider)
{
return ((TemplateContent)value).List.GetReader();
}
}
}

11
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");

7
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@ -16,8 +16,10 @@ 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<XamlIlAstObjectNode>()
.FirstOrDefault(x => x.Type.GetClrType().FullName == "Avalonia.Styling.Style");
.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);
@ -53,8 +55,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
.OfType<XamlIlAstXamlPropertyValueNode>().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(

2
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");

61
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@ -44,7 +44,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
return true;
}
public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo)
{
XamlIlAstNamePropertyReference forgedReference;
@ -63,8 +63,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
xmlOwner += parsedPropertyName.owner;
var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
forgedReference = new XamlIlAstNamePropertyReference(lineInfo,
tref, parsedPropertyName.name, tref);
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 =
@ -75,13 +81,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 +106,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<T>, 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

2
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

34
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)
{
}
}
}

6
tests/Avalonia.DesignerSupport.TestApp/App.xaml

@ -1,6 +1,8 @@
<Application xmlns="https://github.com/avaloniaui">
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Avalonia.DesignerSupport.TestApp.App">
<Application.Styles>
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
</Application.Styles>
</Application>
</Application>

2
tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj

@ -31,6 +31,6 @@
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\Serilog.props" />
</Project>

6
tests/Avalonia.DesignerSupport.TestApp/MainWindow.xaml

@ -1,5 +1,7 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
Title="TESTAPP">
Title="TESTAPP"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Avalonia.DesignerSupport.TestApp.MainWindow">
<Button/>
</Window>
</Window>

17
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@ -118,10 +118,21 @@ namespace Avalonia.DesignerSupport.Tests
cancelled = true;
}
Assert.True(cancelled, $"Message Not Received.");
Assert.NotEqual(0, handle);
proc.Kill();
try
{
proc.Kill();
}
catch
{
//
}
proc.WaitForExit();
Assert.True(cancelled,
$"Message Not Received.\n" + proc.StandardOutput.ReadToEnd() + "\n" +
proc.StandardError.ReadToEnd());
Assert.NotEqual(0, handle);
}
}
}

26
tests/Avalonia.Markup.Xaml.UnitTests/Converters/AvaloniaPropertyConverterTest.cs

@ -8,9 +8,7 @@ using Avalonia.Markup.Xaml.Converters;
using Avalonia.Styling;
using Xunit;
using System.ComponentModel;
using Portable.Xaml;
using Portable.Xaml.Markup;
using Avalonia.Controls;
using Avalonia.Markup.Xaml.XamlIl.Runtime;
namespace Avalonia.Markup.Xaml.UnitTests.Converters
{
@ -91,27 +89,23 @@ namespace Avalonia.Markup.Xaml.UnitTests.Converters
Assert.Equal("Could not find property 'AttachedOwner.NonExistent'.", ex.Message);
}
private ITypeDescriptorContext CreateContext(Style style = null)
{
var tdMock = new Mock<ITypeDescriptorContext>();
var xsc = new Mock<IXamlSchemaContextProvider>();
var sc = Mock.Of<XamlSchemaContext>();
var amb = new Mock<IAmbientProvider>();
var tr = new Mock<IXamlTypeResolver>();
var ps = new Mock<IAvaloniaXamlIlParentStackProvider>();
tdMock.Setup(d => d.GetService(typeof(IAmbientProvider)))
.Returns(amb.Object);
tdMock.Setup(d => d.GetService(typeof(IXamlSchemaContextProvider)))
.Returns(xsc.Object);
tdMock.Setup(d => d.GetService(typeof(IXamlTypeResolver)))
.Returns(tr.Object);
xsc.SetupGet(v => v.SchemaContext)
.Returns(sc);
amb.Setup(v => v.GetFirstAmbientValue(It.IsAny<Portable.Xaml.XamlType>()))
.Returns(style);
amb.Setup(v => v.GetAllAmbientValues(It.IsAny<Portable.Xaml.XamlType>()))
.Returns(new object[] { style });
tdMock.Setup(d => d.GetService(typeof(IAvaloniaXamlIlParentStackProvider)))
.Returns(ps.Object);
ps.SetupGet(v => v.Parents)
.Returns(new object[] {style});
tr.Setup(v => v.Resolve(nameof(Class1)))
.Returns(typeof(Class1));
tr.Setup(v => v.Resolve(nameof(AttachedOwner)))

70
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@ -14,7 +14,6 @@ using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Portable.Xaml;
using System.Collections;
using System.ComponentModel;
using System.Linq;
@ -47,37 +46,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Equal("Foo", target.Content);
}
[Fact]
public void AvaloniaProperty_Without_Getter_And_Setter_Is_Set()
{
// It's not possible to know in compile time if a read-only property has a magic way of being not read-only
if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
return;
var xaml =
@"<local:NonControl xmlns='https://github.com/avaloniaui'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
Foo='55' />";
var target = AvaloniaXamlLoader.Parse<NonControl>(xaml);
Assert.Equal(55, target.GetValue(NonControl.FooProperty));
}
[Fact]
public void AvaloniaProperty_With_Getter_And_No_Setter_Is_Set()
{
if(!AvaloniaXamlLoader.UseLegacyXamlLoader)
return;
var xaml =
@"<local:NonControl xmlns='https://github.com/avaloniaui'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
Bar='bar' />";
var target = AvaloniaXamlLoader.Parse<NonControl>(xaml);
Assert.Equal("bar", target.Bar);
}
[Fact]
public void Attached_Property_Is_Set()
{
@ -159,19 +127,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
}
[Fact]
public void Non_Attached_Property_With_Attached_Property_Syntax_Throws()
{
// 1) It has been allowed in AvaloniaObject.SetValue for ages
// 2) There is no way to know if AddOwner was called in compile-time
if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
return;
var xaml =
@"<ContentControl xmlns='https://github.com/avaloniaui' TextBlock.Text='foo'/>";
XamlTestHelpers.AssertThrowsXamlException(() => AvaloniaXamlLoader.Parse<ContentControl>(xaml));
}
[Fact]
public void ContentControl_ContentTemplate_Is_Functional()
{
@ -595,31 +550,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
}
}
[Fact]
public void Xaml_Binding_Is_Delayed()
{
if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
return;
using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var xaml =
@"<ContentControl xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";
var target = AvaloniaXamlLoader.Parse<ContentControl>(xaml);
Assert.Null(target.Content);
target.DataContext = "Foo";
Assert.Null(target.Content);
DelayedBinding.ApplyBindings(target);
Assert.Equal("Foo", target.Content);
}
}
[Fact]
public void Double_Xaml_Binding_Is_Operational()
{

14
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/EventTests.cs

@ -5,7 +5,6 @@ using System;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Portable.Xaml;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
@ -35,19 +34,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
XamlTestHelpers.AssertThrowsXamlException(() => loader.Load(xaml, rootInstance: target));
}
[Fact]
public void Exception_Is_Not_Thrown_If_Event_Not_Found_In_Design_Mode()
{
// Runtime compiler should properly understand x:Class
if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
return;
var xaml = @"<Button xmlns='https://github.com/avaloniaui' Click='NotFound'/>";
var loader = new AvaloniaXamlLoader { IsDesignMode = true };
var target = new MyButton();
loader.Load(xaml, rootInstance: target);
}
private void RaiseClick(MyButton target)
{
target.RaiseEvent(new KeyEventArgs

4
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

@ -1,13 +1,13 @@
// 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.Xml;
using Avalonia.Controls;
using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Portable.Xaml;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
@ -191,7 +191,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
<TextBlock/>
</Window>";
var loader = new AvaloniaXamlLoader();
var ex = Assert.Throws<XamlObjectWriterException>(() => loader.Load(xaml));
var ex = Assert.Throws<XmlException>(() => loader.Load(xaml));
Assert.Equal(
"Property 'Button.IsDefault' is not registered on 'Avalonia.Controls.TextBlock'.",

42
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(@"
<Window
xmlns='https://github.com/avaloniaui'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests;assembly=Avalonia.Markup.Xaml.UnitTests'
>
<Window.Styles>
<Style Selector='TextBox'>
<Setter Property='local:XamlIlBugTestsStaticClassWithAttachedProperty.TestInt' Value='100'/>
</Style>
</Window.Styles>
<TextBox/>
</Window>
");
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<int> TestIntProperty = AvaloniaProperty
.RegisterAttached<Control, int>("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);
}
}
}

3
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlTestHelpers.cs

@ -1,6 +1,5 @@
using System;
using System.Xml;
using Portable.Xaml;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{
@ -14,7 +13,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
}
catch (Exception e)
{
if(e is XamlObjectWriterException || e is XmlException)
if(e is XmlException)
return;
}
throw new Exception("Expected to throw xaml exception");

Loading…
Cancel
Save