Browse Source

Nullable annotations for Markup.Xaml

pull/10608/head
Julien Lebosquain 4 years ago
parent
commit
e3c1cbd2e0
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 2
      src/Avalonia.Base/Styling/ITemplate.cs
  2. 19
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  3. 4
      src/Avalonia.Controls/Templates/IControlTemplate.cs
  4. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  5. 5
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  6. 14
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
  7. 6
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs
  8. 11
      src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs
  9. 8
      src/Markup/Avalonia.Markup.Xaml/Converters/ColorToBrushConverter.cs
  10. 10
      src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs
  11. 13
      src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs
  12. 9
      src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs
  13. 13
      src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs
  14. 31
      src/Markup/Avalonia.Markup.Xaml/Extensions.cs
  15. 12
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
  16. 10
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/ArrayElementPlugin.cs
  17. 36
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CommandAccessorPlugin.cs
  18. 54
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
  19. 12
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/FindVisualAncestorNode.cs
  20. 6
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/MethodAccessorPlugin.cs
  21. 14
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/ObservableStreamPlugin.cs
  22. 52
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs
  23. 11
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorPlugin.cs
  24. 6
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
  25. 18
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/TaskStreamPlugin.cs
  26. 4
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
  27. 3
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/On.cs
  28. 6
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs
  29. 4
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs
  30. 27
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs
  31. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs
  32. 11
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs
  33. 34
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  34. 8
      src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs
  35. 2
      src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderConfiguration.cs
  36. 3
      src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs
  37. 3
      src/Markup/Avalonia.Markup.Xaml/Styling/MergeResourceInclude.cs
  38. 2
      src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs
  39. 6
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  40. 6
      src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs
  41. 10
      src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
  42. 8
      src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs
  43. 8
      src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs
  44. 17
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  45. 12
      src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
  46. 4
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs
  47. 40
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  48. 3
      src/Markup/Avalonia.Markup/Data/Binding.cs
  49. 5
      src/Markup/Avalonia.Markup/Data/BindingBase.cs
  50. 27
      src/Markup/Avalonia.Markup/Data/TemplateBinding.cs
  51. 9
      src/Markup/Avalonia.Markup/Markup/Data/DelayedBinding.cs
  52. 6
      src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs
  53. 8
      src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs
  54. 12
      src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
  55. 6
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  56. 11
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

2
src/Avalonia.Base/Styling/ITemplate.cs

@ -2,6 +2,6 @@
{
public interface ITemplate
{
object Build();
object? Build();
}
}

19
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -286,14 +286,17 @@ namespace Avalonia.Controls.Primitives
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.Control)?.Log(this, "Creating control template");
var (child, nameScope) = template.Build(this);
ApplyTemplatedParent(child, this);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
var e = new TemplateAppliedEventArgs(nameScope);
OnApplyTemplate(e);
RaiseEvent(e);
if (template.Build(this) is { } templateResult)
{
var (child, nameScope) = templateResult;
ApplyTemplatedParent(child, this);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
var e = new TemplateAppliedEventArgs(nameScope);
OnApplyTemplate(e);
RaiseEvent(e);
}
}
_appliedTemplate = template;

4
src/Avalonia.Controls/Templates/IControlTemplate.cs

@ -1,13 +1,11 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
namespace Avalonia.Controls.Templates
{
/// <summary>
/// Interface representing a template used to build a <see cref="TemplatedControl"/>.
/// </summary>
public interface IControlTemplate : ITemplate<TemplatedControl, ControlTemplateResult>
public interface IControlTemplate : ITemplate<TemplatedControl, ControlTemplateResult?>
{
}

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -58,7 +58,6 @@
<Compile Include="XamlIl\Runtime\IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs" />
<Compile Include="XamlIl\Runtime\XamlIlRuntimeHelpers.cs" />
<Compile Include="XamlLoadException.cs" />
<Compile Include="..\Avalonia.Markup\Markup\Parsers\BindingExpressionGrammar.cs" />
<Compile Include="XamlTypes.cs" />
</ItemGroup>
<ItemGroup>
@ -69,6 +68,7 @@
<Import Project="..\..\..\build\ApiDiff.props" />
<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" />

5
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@ -1,8 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Avalonia.Platform;
#nullable enable
namespace Avalonia.Markup.Xaml
{
/// <summary>
@ -79,7 +78,7 @@ namespace Avalonia.Markup.Xaml
var compiledLoader = assetLocator.GetAssembly(uri, baseUri)
?.GetType("CompiledAvaloniaXaml.!XamlLoader")
?.GetMethod("TryLoad", new[] { typeof(System.IServiceProvider), typeof(string) });
?.GetMethod("TryLoad", new[] { typeof(IServiceProvider), typeof(string) });
if (compiledLoader != null)
{
var compiledResult = compiledLoader.Invoke(null, new object?[] { sp, absoluteUri.ToString()});

14
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs

@ -14,18 +14,20 @@ namespace Avalonia.Markup.Xaml.Converters
[RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)]
public class AvaloniaPropertyTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var registry = AvaloniaPropertyRegistry.Instance;
var (ns, owner, propertyName) = PropertyParser.Parse(new CharacterReader(((string)value).AsSpan()));
var ownerType = TryResolveOwnerByName(context, ns, owner);
var targetType = context.GetFirstParent<ControlTemplate>()?.TargetType ??
context.GetFirstParent<Style>()?.Selector?.TargetType ??
var targetType = context?.GetFirstParent<ControlTemplate>()?.TargetType ??
context?.GetFirstParent<Style>()?.Selector?.TargetType ??
typeof(Control);
var effectiveOwner = ownerType ?? targetType;
var property = registry.FindRegistered(effectiveOwner, propertyName);
@ -51,11 +53,11 @@ namespace Avalonia.Markup.Xaml.Converters
}
[RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)]
private static Type TryResolveOwnerByName(ITypeDescriptorContext context, string ns, string owner)
private static Type? TryResolveOwnerByName(ITypeDescriptorContext? context, string? ns, string? owner)
{
if (owner != null)
{
var result = context.ResolveType(ns, owner);
var result = context?.ResolveType(ns, owner);
if (result == null)
{

6
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaUriTypeConverter.cs

@ -6,12 +6,14 @@ namespace Avalonia.Markup.Xaml.Converters
{
public class AvaloniaUriTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var s = value as string;
if (s == null)

11
src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs

@ -1,20 +1,21 @@
using System;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class BitmapTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var s = (string)value;
var uri = s.StartsWith("/")
@ -25,7 +26,7 @@ namespace Avalonia.Markup.Xaml.Converters
return new Bitmap(uri.LocalPath);
var assets = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
return new Bitmap(assets.Open(uri, context.GetContextBaseUri()));
return new Bitmap(assets.Open(uri, context?.GetContextBaseUri()));
}
}
}

8
src/Markup/Avalonia.Markup.Xaml/Converters/ColorToBrushConverter.cs

@ -23,7 +23,7 @@ namespace Avalonia.Markup.Xaml.Converters
/// If <paramref name="value"/> is a <see cref="Color"/> and <paramref name="targetType"/>
/// is <see cref="IBrush"/> then converts the color to a solid color brush.
/// </returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return Convert(value, targetType);
}
@ -40,7 +40,7 @@ namespace Avalonia.Markup.Xaml.Converters
/// If <paramref name="value"/> is an <see cref="ISolidColorBrush"/> and <paramref name="targetType"/>
/// is <see cref="Color"/> then converts the solid color brush to a color.
/// </returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return ConvertBack(value, targetType);
}
@ -55,7 +55,7 @@ namespace Avalonia.Markup.Xaml.Converters
/// If <paramref name="value"/> is a <see cref="Color"/> and <paramref name="targetType"/>
/// is <see cref="IBrush"/> then converts the color to a solid color brush.
/// </returns>
public static object Convert(object value, Type targetType)
public static object? Convert(object? value, Type? targetType)
{
if (targetType == typeof(IBrush) && value is Color c)
{
@ -75,7 +75,7 @@ namespace Avalonia.Markup.Xaml.Converters
/// If <paramref name="value"/> is an <see cref="ISolidColorBrush"/> and <paramref name="targetType"/>
/// is <see cref="Color"/> then converts the solid color brush to a color.
/// </returns>
public static object ConvertBack(object value, Type targetType)
public static object? ConvertBack(object? value, Type? targetType)
{
if (targetType == typeof(Color) && value is ISolidColorBrush brush)
{

10
src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs

@ -1,24 +1,24 @@
using System;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Media;
namespace Avalonia.Markup.Xaml.Converters
{
public class FontFamilyTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var s = (string)value;
return FontFamily.Parse(s, context.GetContextBaseUri());
return FontFamily.Parse(s, context?.GetContextBaseUri());
}
}
}

13
src/Markup/Avalonia.Markup.Xaml/Converters/IconTypeConverter.cs

@ -2,20 +2,21 @@
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using System;
using System.ComponentModel;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class IconTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var path = value as string;
if (path != null)
@ -32,7 +33,7 @@ namespace Avalonia.Markup.Xaml.Converters
throw new NotSupportedException();
}
private static WindowIcon CreateIconFromPath(ITypeDescriptorContext context, string s)
private static WindowIcon CreateIconFromPath(ITypeDescriptorContext? context, string s)
{
var uri = s.StartsWith("/")
? new Uri(s, UriKind.Relative)
@ -41,7 +42,7 @@ namespace Avalonia.Markup.Xaml.Converters
if(uri.IsAbsoluteUri && uri.IsFile)
return new WindowIcon(uri.LocalPath);
var assets = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
return new WindowIcon(assets.Open(uri, context.GetContextBaseUri()));
return new WindowIcon(assets.Open(uri, context?.GetContextBaseUri()));
}
}
}

9
src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs

@ -1,20 +1,19 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Utilities;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
using Avalonia.Utilities;
public class PointsListTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var points = new List<Point>();

13
src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs

@ -1,18 +1,13 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class TimeSpanTypeConverter : System.ComponentModel.TimeSpanConverter
public class TimeSpanTypeConverter : TimeSpanConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <inheritdoc />
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var valueStr = (string)value;
if (!valueStr.Contains(':'))

31
src/Markup/Avalonia.Markup.Xaml/Extensions.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Controls;
@ -11,38 +10,38 @@ namespace Avalonia.Markup.Xaml
{
internal static class Extensions
{
public static T GetService<T>(this IServiceProvider sp) => (T)sp?.GetService(typeof(T));
public static Uri GetContextBaseUri(this IServiceProvider ctx) => ctx.GetService<IUriContext>().BaseUri;
public static T? GetService<T>(this IServiceProvider sp) => (T?)sp.GetService(typeof(T));
public static T GetRequiredService<T>(this IServiceProvider sp)
=> sp.GetService<T>() ?? throw new InvalidOperationException($"Service {typeof(T)} hasn't been registered");
public static T GetFirstParent<T>(this IServiceProvider ctx) where T : class
=> ctx.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>().FirstOrDefault();
public static Uri? GetContextBaseUri(this IServiceProvider ctx) => ctx.GetService<IUriContext>()?.BaseUri;
public static T GetLastParent<T>(this IServiceProvider ctx) where T : class
=> ctx.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>().LastOrDefault();
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)
{
return sp.GetService<IAvaloniaXamlIlParentStackProvider>().Parents.OfType<T>();
}
=> sp.GetService<IAvaloniaXamlIlParentStackProvider>()?.Parents.OfType<T>() ?? Enumerable.Empty<T>();
public static bool IsInControlTemplate(this IServiceProvider sp) => sp.GetService<IAvaloniaXamlIlControlTemplateProvider>() != null;
[RequiresUnreferencedCode(TrimmingMessages.XamlTypeResolvedRequiresUnreferenceCodeMessage)]
public static Type ResolveType(this IServiceProvider ctx, string namespacePrefix, string type)
public static Type ResolveType(this IServiceProvider ctx, string? namespacePrefix, string type)
{
var tr = ctx.GetService<IXamlTypeResolver>();
string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}";
return tr?.Resolve(name);
return tr?.Resolve(name) ?? throw new XamlLoadException($"Could not find type '{name}'.");
}
public static object GetDefaultAnchor(this IServiceProvider provider)
public static object? GetDefaultAnchor(this IServiceProvider provider)
{
// If the target is not a control, so we need to find an anchor that will let us look
// up named controls and style resources. First look for the closest Control in
// the context.
object anchor = provider.GetFirstParent<Control>();
object? anchor = provider.GetFirstParent<Control>();
if (anchor is null)
{

12
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs

@ -35,7 +35,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
};
}
private protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty targetProperty, object anchor, bool enableDataValidation)
private protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty? targetProperty, object? anchor, bool enableDataValidation)
{
if (Source != null)
{
@ -61,8 +61,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
}
else
{
var styledElement = target as StyledElement
?? anchor as StyledElement
?? throw new ArgumentException($"Cannot find a valid {nameof(StyledElement)} to use as the binding source.");
return CreateSourceObserver(
(target as StyledElement) ?? (anchor as StyledElement),
styledElement,
Path.BuildExpression(enableDataValidation));
}
}
@ -70,8 +74,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
[ConstructorArgument("path")]
public CompiledBindingPath Path { get; set; }
public object Source { get; set; }
public object? Source { get; set; }
public Type DataType { get; set; }
public Type? DataType { get; set; }
}
}

10
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/ArrayElementPlugin.cs

@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Avalonia.Data;
using Avalonia.Data.Core.Plugins;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
class ArrayElementPlugin : IPropertyAccessorPlugin
internal class ArrayElementPlugin : IPropertyAccessorPlugin
{
private readonly int[] _indices;
private readonly Type _elementType;
@ -25,7 +23,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object> reference, string propertyName)
public IPropertyAccessor? Start(WeakReference<object?> reference, string propertyName)
{
if (reference.TryGetTarget(out var target) && target is Array arr)
{
@ -48,9 +46,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public override Type PropertyType { get; }
public override object Value => _reference.TryGetTarget(out var arr) ? arr.GetValue(_indices) : null;
public override object? Value => _reference.TryGetTarget(out var arr) ? arr.GetValue(_indices) : null;
public override bool SetValue(object value, BindingPriority priority)
public override bool SetValue(object? value, BindingPriority priority)
{
if (_reference.TryGetTarget(out var arr))
{

36
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CommandAccessorPlugin.cs

@ -2,8 +2,6 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Avalonia.Data;
using Avalonia.Data.Core.Plugins;
@ -13,11 +11,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
internal class CommandAccessorPlugin : IPropertyAccessorPlugin
{
private readonly Action<object, object> _execute;
private readonly Func<object, object, bool> _canExecute;
private readonly Action<object, object?> _execute;
private readonly Func<object, object?, bool>? _canExecute;
private readonly ISet<string> _dependsOnProperties;
public CommandAccessorPlugin(Action<object, object> execute, Func<object, object, bool> canExecute, ISet<string> dependsOnProperties)
public CommandAccessorPlugin(Action<object, object?> execute, Func<object, object?, bool>? canExecute, ISet<string> dependsOnProperties)
{
_execute = execute;
_canExecute = canExecute;
@ -31,18 +29,18 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object> reference, string propertyName)
public IPropertyAccessor Start(WeakReference<object?> reference, string propertyName)
{
return new CommandAccessor(reference, _execute, _canExecute, _dependsOnProperties);
}
private sealed class CommandAccessor : PropertyAccessorBase
{
private readonly WeakReference<object> _reference;
private Command _command;
private readonly WeakReference<object?> _reference;
private readonly Command _command;
private readonly ISet<string> _dependsOnProperties;
public CommandAccessor(WeakReference<object> reference, Action<object, object> execute, Func<object, object, bool> canExecute, ISet<string> dependsOnProperties)
public CommandAccessor(WeakReference<object?> reference, Action<object, object?> execute, Func<object, object?, bool>? canExecute, ISet<string> dependsOnProperties)
{
_reference = reference ?? throw new ArgumentNullException(nameof(reference));
_dependsOnProperties = dependsOnProperties;
@ -50,7 +48,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
public override object Value => _reference.TryGetTarget(out var _) ? _command : null;
public override object? Value => _reference.TryGetTarget(out _) ? _command : null;
private void RaiseCanExecuteChanged()
{
@ -59,13 +57,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
private sealed class Command : ICommand
{
private readonly WeakReference<object> _target;
private readonly Action<object, object> _execute;
private readonly Func<object, object, bool> _canExecute;
private readonly WeakReference<object?> _target;
private readonly Action<object, object?> _execute;
private readonly Func<object, object?, bool>? _canExecute;
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
public Command(WeakReference<object> target, Action<object, object> execute, Func<object, object, bool> canExecute)
public Command(WeakReference<object?> target, Action<object, object?> execute, Func<object, object?, bool>? canExecute)
{
_target = target;
_execute = execute;
@ -78,7 +76,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
, Threading.DispatcherPriority.Input);
}
public bool CanExecute(object parameter)
public bool CanExecute(object? parameter)
{
if (_target.TryGetTarget(out var target))
{
@ -91,7 +89,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return false;
}
public void Execute(object parameter)
public void Execute(object? parameter)
{
if (_target.TryGetTarget(out var target))
{
@ -102,12 +100,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public override Type PropertyType => typeof(ICommand);
public override bool SetValue(object value, BindingPriority priority)
public override bool SetValue(object? value, BindingPriority priority)
{
return false;
}
void OnNotifyPropertyChanged(object sender, PropertyChangedEventArgs e)
private void OnNotifyPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (string.IsNullOrEmpty(e.PropertyName) || _dependsOnProperties.Contains(e.PropertyName))
{

54
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs

@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public CompiledBindingPath()
=> _elements = Array.Empty<ICompiledBindingPathElement>();
internal CompiledBindingPath(ICompiledBindingPathElement[] elements, object rawSource)
internal CompiledBindingPath(ICompiledBindingPathElement[] elements, object? rawSource)
{
_elements = elements;
RawSource = rawSource;
@ -26,14 +26,14 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.CompiledBindingSafeSupressWarningMessage)]
internal ExpressionNode BuildExpression(bool enableValidation)
{
ExpressionNode pathRoot = null;
ExpressionNode path = null;
ExpressionNode? pathRoot = null;
ExpressionNode? path = null;
foreach (var element in _elements)
{
ExpressionNode node = null;
ExpressionNode? node;
switch (element)
{
case NotExpressionPathElement _:
case NotExpressionPathElement:
node = new LogicalNotNode();
break;
case PropertyElement prop:
@ -54,7 +54,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
case AncestorPathElement ancestor:
node = new FindAncestorNode(ancestor.AncestorType, ancestor.Level);
break;
case SelfPathElement _:
case SelfPathElement:
node = new SelfNode();
break;
case ElementNameElement name:
@ -70,7 +70,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
throw new InvalidOperationException($"Unknown binding path element type {element.GetType().FullName}");
}
path = pathRoot is null ? (pathRoot = node) : path.Next = node;
path = pathRoot is null ? (pathRoot = node) : path!.Next = node;
}
return pathRoot ?? new EmptyExpressionNode();
@ -81,16 +81,17 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal SourceMode SourceMode => Array.Exists(_elements, e => e is IControlSourceBindingPathElement)
? SourceMode.Control : SourceMode.Data;
internal object RawSource { get; }
internal object? RawSource { get; }
/// <inheritdoc />
public override string ToString()
=> string.Concat((IEnumerable<ICompiledBindingPathElement>) _elements);
}
public class CompiledBindingPathBuilder
{
private object _rawSource;
private List<ICompiledBindingPathElement> _elements = new List<ICompiledBindingPathElement>();
private object? _rawSource;
private readonly List<ICompiledBindingPathElement> _elements = new();
public CompiledBindingPathBuilder Not()
{
@ -98,7 +99,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
public CompiledBindingPathBuilder Property(IPropertyInfo info, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory)
public CompiledBindingPathBuilder Property(IPropertyInfo info, Func<WeakReference<object?>, IPropertyInfo, IPropertyAccessor> accessorFactory)
{
_elements.Add(new PropertyElement(info, accessorFactory, _elements.Count == 0));
return this;
@ -110,7 +111,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
public CompiledBindingPathBuilder Command(string methodName, Action<object, object> executeHelper, Func<object, object, bool> canExecuteHelper, string[] dependsOnProperties)
public CompiledBindingPathBuilder Command(string methodName, Action<object, object?> executeHelper, Func<object, object?, bool>? canExecuteHelper, string[]? dependsOnProperties)
{
_elements.Add(new MethodAsCommandElement(methodName, executeHelper, canExecuteHelper, dependsOnProperties ?? Array.Empty<string>()));
return this;
@ -163,7 +164,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
public CompiledBindingPathBuilder SetRawSource(object rawSource)
public CompiledBindingPathBuilder SetRawSource(object? rawSource)
{
_rawSource = rawSource;
return this;
@ -187,7 +188,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
private readonly bool _isFirstElement;
public PropertyElement(IPropertyInfo property, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory, bool isFirstElement)
public PropertyElement(IPropertyInfo property, Func<WeakReference<object?>, IPropertyInfo, IPropertyAccessor> accessorFactory, bool isFirstElement)
{
Property = property;
AccessorFactory = accessorFactory;
@ -196,7 +197,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public IPropertyInfo Property { get; }
public Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
public Func<WeakReference<object?>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
public override string ToString()
=> _isFirstElement ? Property.Name : $".{Property.Name}";
@ -206,7 +207,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
public MethodAsDelegateElement(RuntimeMethodHandle method, RuntimeTypeHandle delegateType)
{
Method = (MethodInfo)MethodBase.GetMethodFromHandle(method);
Method = MethodBase.GetMethodFromHandle(method) as MethodInfo
?? throw new ArgumentException("Invalid method handle", nameof(method));
DelegateType = Type.GetTypeFromHandle(delegateType);
}
@ -217,7 +219,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class MethodAsCommandElement : ICompiledBindingPathElement
{
public MethodAsCommandElement(string methodName, Action<object, object> executeHelper, Func<object, object, bool> canExecuteHelper, string[] dependsOnElements)
public MethodAsCommandElement(string methodName, Action<object, object?> executeHelper, Func<object, object?, bool>? canExecuteHelper, string[] dependsOnElements)
{
MethodName = methodName;
ExecuteMethod = executeHelper;
@ -226,8 +228,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
public string MethodName { get; }
public Action<object, object> ExecuteMethod { get; }
public Func<object, object, bool> CanExecuteMethod { get; }
public Action<object, object?> ExecuteMethod { get; }
public Func<object, object?, bool>? CanExecuteMethod { get; }
public HashSet<string> DependsOnProperties { get; }
}
@ -240,7 +242,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
Type Type { get; }
Func<object, object> Cast { get; }
Func<object?, object?> Cast { get; }
}
internal class TaskStreamPathElement<T> : IStronglyTypedStreamElement
@ -267,13 +269,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class AncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
{
public AncestorPathElement(Type ancestorType, int level)
public AncestorPathElement(Type? ancestorType, int level)
{
AncestorType = ancestorType;
Level = level;
}
public Type AncestorType { get; }
public Type? AncestorType { get; }
public int Level { get; }
public override string ToString()
@ -282,13 +284,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class VisualAncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
{
public VisualAncestorPathElement(Type ancestorType, int level)
public VisualAncestorPathElement(Type? ancestorType, int level)
{
AncestorType = ancestorType;
Level = level;
}
public Type AncestorType { get; }
public Type? AncestorType { get; }
public int Level { get; }
}
@ -323,7 +325,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class TypeCastPathElement<T> : ITypeCastElement
{
private static object TryCast(object obj)
private static object? TryCast(object? obj)
{
if (obj is T result)
return result;
@ -332,7 +334,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public Type Type => typeof(T);
public Func<object, object> Cast => TryCast;
public Func<object?, object?> Cast => TryCast;
public override string ToString()
=> $"({Type.FullName})";

12
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/FindVisualAncestorNode.cs

@ -5,13 +5,13 @@ using Avalonia.Reactive;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
class FindVisualAncestorNode : ExpressionNode
internal class FindVisualAncestorNode : ExpressionNode
{
private readonly int _level;
private readonly Type _ancestorType;
private IDisposable _subscription;
private readonly Type? _ancestorType;
private IDisposable? _subscription;
public FindVisualAncestorNode(Type ancestorType, int level)
public FindVisualAncestorNode(Type? ancestorType, int level)
{
_level = level;
_ancestorType = ancestorType;
@ -32,9 +32,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
}
protected override void StartListeningCore(WeakReference<object> reference)
protected override void StartListeningCore(WeakReference<object?> reference)
{
if (reference.TryGetTarget(out object target) && target is Visual visual)
if (reference.TryGetTarget(out object? target) && target is Visual visual)
{
_subscription = VisualLocator.Track(visual, _level, _ancestorType).Subscribe(ValueChanged);
}

6
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/MethodAccessorPlugin.cs

@ -1,19 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text;
using Avalonia.Data;
using Avalonia.Data.Core.Plugins;
#nullable enable
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
internal class MethodAccessorPlugin : IPropertyAccessorPlugin
{
private MethodInfo _method;
private readonly MethodInfo _method;
private readonly Type _delegateType;
public MethodAccessorPlugin(MethodInfo method, Type delegateType)

14
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/ObservableStreamPlugin.cs

@ -1,33 +1,31 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Avalonia.Data.Core.Plugins;
using Avalonia.Reactive;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
class ObservableStreamPlugin<T> : IStreamPlugin
internal class ObservableStreamPlugin<T> : IStreamPlugin
{
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public bool Match(WeakReference<object> reference)
public bool Match(WeakReference<object?> reference)
{
return reference.TryGetTarget(out var target) && target is IObservable<T>;
}
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public IObservable<object> Start(WeakReference<object> reference)
public IObservable<object?> Start(WeakReference<object?> reference)
{
if (!(reference.TryGetTarget(out var target) && target is IObservable<T> obs))
{
return Observable.Empty<object>();
return Observable.Empty<object?>();
}
else if (target is IObservable<object> obj)
else if (target is IObservable<object?> obj)
{
return obj;
}
return obs.Select(x => (object)x);
return obs.Select(x => (object?)x);
}
}
}

52
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs

@ -11,29 +11,29 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
public static class PropertyInfoAccessorFactory
{
public static IPropertyAccessor CreateInpcPropertyAccessor(WeakReference<object> target, IPropertyInfo property)
public static IPropertyAccessor CreateInpcPropertyAccessor(WeakReference<object?> target, IPropertyInfo property)
=> new InpcPropertyAccessor(target, property);
public static IPropertyAccessor CreateAvaloniaPropertyAccessor(WeakReference<object> target, IPropertyInfo property)
=> new AvaloniaPropertyAccessor(new WeakReference<AvaloniaObject>((AvaloniaObject)(target.TryGetTarget(out var o) ? o : null)), (AvaloniaProperty)property);
public static IPropertyAccessor CreateAvaloniaPropertyAccessor(WeakReference<object?> target, IPropertyInfo property)
=> new AvaloniaPropertyAccessor(new WeakReference<AvaloniaObject?>((AvaloniaObject?)(target.TryGetTarget(out var o) ? o : null)), (AvaloniaProperty)property);
public static IPropertyAccessor CreateIndexerPropertyAccessor(WeakReference<object> target, IPropertyInfo property, int argument)
public static IPropertyAccessor CreateIndexerPropertyAccessor(WeakReference<object?> target, IPropertyInfo property, int argument)
=> new IndexerAccessor(target, property, argument);
}
internal class AvaloniaPropertyAccessor : PropertyAccessorBase
{
private readonly WeakReference<AvaloniaObject> _reference;
private readonly WeakReference<AvaloniaObject?> _reference;
private readonly AvaloniaProperty _property;
private IDisposable _subscription;
private IDisposable? _subscription;
public AvaloniaPropertyAccessor(WeakReference<AvaloniaObject> reference, AvaloniaProperty property)
public AvaloniaPropertyAccessor(WeakReference<AvaloniaObject?> reference, AvaloniaProperty property)
{
_reference = reference ?? throw new ArgumentNullException(nameof(reference));;
_property = property ?? throw new ArgumentNullException(nameof(property));;
_reference = reference ?? throw new ArgumentNullException(nameof(reference));
_property = property ?? throw new ArgumentNullException(nameof(property));
}
public AvaloniaObject Instance
public AvaloniaObject? Instance
{
get
{
@ -43,13 +43,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
public override Type PropertyType => _property.PropertyType;
public override object Value => Instance?.GetValue(_property);
public override object? Value => Instance?.GetValue(_property);
public override bool SetValue(object value, BindingPriority priority)
public override bool SetValue(object? value, BindingPriority priority)
{
if (!_property.IsReadOnly)
if (!_property.IsReadOnly && Instance is { } instance)
{
Instance.SetValue(_property, value, priority);
instance.SetValue(_property, value, priority);
return true;
}
@ -70,10 +70,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class InpcPropertyAccessor : PropertyAccessorBase, IWeakEventSubscriber<PropertyChangedEventArgs>
{
protected readonly WeakReference<object> _reference;
protected readonly WeakReference<object?> _reference;
private readonly IPropertyInfo _property;
public InpcPropertyAccessor(WeakReference<object> reference, IPropertyInfo property)
public InpcPropertyAccessor(WeakReference<object?> reference, IPropertyInfo property)
{
_reference = reference ?? throw new ArgumentNullException(nameof(reference));
_property = property ?? throw new ArgumentNullException(nameof(property));
@ -81,7 +81,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public override Type PropertyType => _property.PropertyType;
public override object Value
public override object? Value
{
get
{
@ -89,7 +89,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
}
public override bool SetValue(object value, BindingPriority priority)
public override bool SetValue(object? value, BindingPriority priority)
{
if (_property.CanSet && _reference.TryGetTarget(out var o))
{
@ -103,7 +103,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return false;
}
public void OnEvent(object sender, WeakEvent ev, PropertyChangedEventArgs e)
public void OnEvent(object? sender, WeakEvent ev, PropertyChangedEventArgs e)
{
if (e.PropertyName == _property.Name || string.IsNullOrEmpty(e.PropertyName))
{
@ -144,9 +144,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class IndexerAccessor : InpcPropertyAccessor, IWeakEventSubscriber<NotifyCollectionChangedEventArgs>
{
private int _index;
private readonly int _index;
public IndexerAccessor(WeakReference<object> target, IPropertyInfo basePropertyInfo, int argument)
public IndexerAccessor(WeakReference<object?> target, IPropertyInfo basePropertyInfo, int argument)
:base(target, basePropertyInfo)
{
_index = argument;
@ -167,7 +167,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
WeakEvents.CollectionChanged.Unsubscribe(incc, this);
}
public void OnEvent(object sender, WeakEvent ev, NotifyCollectionChangedEventArgs args)
public void OnEvent(object? sender, WeakEvent ev, NotifyCollectionChangedEventArgs args)
{
if (ShouldNotifyListeners(args))
{
@ -175,7 +175,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
}
bool ShouldNotifyListeners(NotifyCollectionChangedEventArgs e)
private bool ShouldNotifyListeners(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
@ -185,12 +185,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return _index >= e.OldStartingIndex;
case NotifyCollectionChangedAction.Replace:
return _index >= e.NewStartingIndex &&
_index < e.NewStartingIndex + e.NewItems.Count;
_index < e.NewStartingIndex + e.NewItems!.Count;
case NotifyCollectionChangedAction.Move:
return (_index >= e.NewStartingIndex &&
_index < e.NewStartingIndex + e.NewItems.Count) ||
_index < e.NewStartingIndex + e.NewItems!.Count) ||
(_index >= e.OldStartingIndex &&
_index < e.OldStartingIndex + e.OldItems.Count);
_index < e.OldStartingIndex + e.OldItems!.Count);
case NotifyCollectionChangedAction.Reset:
return true;
}

11
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorPlugin.cs

@ -1,20 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
class PropertyInfoAccessorPlugin : IPropertyAccessorPlugin
internal class PropertyInfoAccessorPlugin : IPropertyAccessorPlugin
{
private readonly IPropertyInfo _propertyInfo;
private readonly Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> _accessorFactory;
private readonly Func<WeakReference<object?>, IPropertyInfo, IPropertyAccessor> _accessorFactory;
public PropertyInfoAccessorPlugin(IPropertyInfo propertyInfo, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory)
public PropertyInfoAccessorPlugin(IPropertyInfo propertyInfo, Func<WeakReference<object?>, IPropertyInfo, IPropertyAccessor> accessorFactory)
{
_propertyInfo = propertyInfo;
_accessorFactory = accessorFactory;
@ -27,7 +24,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
[RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)]
public IPropertyAccessor Start(WeakReference<object> reference, string propertyName)
public IPropertyAccessor Start(WeakReference<object?> reference, string propertyName)
{
Debug.Assert(_propertyInfo.Name == propertyName);
return _accessorFactory(reference, _propertyInfo);

6
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs

@ -5,14 +5,14 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
internal class StrongTypeCastNode : TypeCastNode
{
private Func<object, object> _cast;
private readonly Func<object?, object?> _cast;
public StrongTypeCastNode(Type type, Func<object, object> cast) : base(type)
public StrongTypeCastNode(Type type, Func<object?, object?> cast) : base(type)
{
_cast = cast;
}
protected override object Cast(object value)
protected override object? Cast(object? value)
=> _cast(value);
}
}

18
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/TaskStreamPlugin.cs

@ -7,20 +7,20 @@ using Avalonia.Reactive;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
class TaskStreamPlugin<T> : IStreamPlugin
internal class TaskStreamPlugin<T> : IStreamPlugin
{
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public bool Match(WeakReference<object> reference)
public bool Match(WeakReference<object?> reference)
{
return reference.TryGetTarget(out var target) && target is Task<T>;
}
[RequiresUnreferencedCode(TrimmingMessages.StreamPluginRequiresUnreferencedCodeMessage)]
public IObservable<object> Start(WeakReference<object> reference)
public IObservable<object?> Start(WeakReference<object?> reference)
{
if(!(reference.TryGetTarget(out var target) && target is Task<T> task))
{
return Observable.Empty<object>();
return Observable.Empty<object?>();
}
switch (task.Status)
@ -29,9 +29,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
case TaskStatus.Faulted:
return HandleCompleted(task);
default:
var subject = new LightweightSubject<object>();
var subject = new LightweightSubject<object?>();
task.ContinueWith(
x => HandleCompleted(task).Subscribe(subject),
_ => HandleCompleted(task).Subscribe(subject),
TaskScheduler.FromCurrentSynchronizationContext())
.ConfigureAwait(false);
return subject;
@ -39,14 +39,14 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
}
private static IObservable<object> HandleCompleted(Task<T> task)
private static IObservable<object?> HandleCompleted(Task<T> task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
return Observable.Return((object)task.Result);
return Observable.Return((object?)task.Result);
case TaskStatus.Faulted:
return Observable.Return(new BindingNotification(task.Exception, BindingErrorType.Error));
return Observable.Return(new BindingNotification(task.Exception!, BindingErrorType.Error));
default:
throw new AvaloniaInternalException("HandleCompleted called for non-completed Task.");
}

4
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs

@ -4,8 +4,6 @@ using Avalonia.Data;
using Avalonia.Markup.Xaml.Converters;
using Avalonia.Media;
#nullable enable
namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class DynamicResourceExtension : IBinding
@ -31,7 +29,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var provideTarget = serviceProvider.GetService<IProvideValueTarget>();
if (!(provideTarget.TargetObject is StyledElement))
if (provideTarget?.TargetObject is not StyledElement)
{
_anchor = serviceProvider.GetFirstParent<StyledElement>() ??
serviceProvider.GetFirstParent<IResourceProvider>() ??

3
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/On.cs

@ -1,5 +1,4 @@
#nullable enable
using System.Collections.Generic;
using System.Collections.Generic;
using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.MarkupExtensions;

6
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs

@ -1,6 +1,4 @@
#nullable enable
using System;
using Avalonia.Metadata;
using Avalonia.Platform;
@ -20,7 +18,7 @@ public sealed class OnFormFactorExtension : OnFormFactorExtensionBase<object, On
public static bool ShouldProvideOption(IServiceProvider serviceProvider, FormFactorType option)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().FormFactor == option;
return serviceProvider.GetService<IRuntimePlatform>()?.GetRuntimeInfo().FormFactor == option;
}
}
@ -38,7 +36,7 @@ public sealed class OnFormFactorExtension<TReturn> : OnFormFactorExtensionBase<T
public static bool ShouldProvideOption(IServiceProvider serviceProvider, FormFactorType option)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().FormFactor == option;
return serviceProvider.GetService<IRuntimePlatform>()?.GetRuntimeInfo().FormFactor == option;
}
}

4
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs

@ -1,6 +1,4 @@
#nullable enable
using System;
using Avalonia.Compatibility;
using Avalonia.Compatibility;
using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.MarkupExtensions;

27
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ReflectionBindingExtension.cs

@ -2,7 +2,6 @@ using Avalonia.Data;
using System;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
namespace Avalonia.Markup.Xaml.MarkupExtensions
@ -21,11 +20,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public Binding ProvideValue(IServiceProvider serviceProvider)
{
var descriptorContext = (ITypeDescriptorContext)serviceProvider;
return new Binding
{
TypeResolver = descriptorContext.ResolveType,
TypeResolver = serviceProvider.ResolveType,
Converter = Converter,
ConverterParameter = ConverterParameter,
ElementName = ElementName,
@ -36,33 +33,33 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
Source = Source,
StringFormat = StringFormat,
RelativeSource = RelativeSource,
DefaultAnchor = new WeakReference(descriptorContext.GetDefaultAnchor()),
DefaultAnchor = new WeakReference(serviceProvider.GetDefaultAnchor()),
TargetNullValue = TargetNullValue,
NameScope = new WeakReference<INameScope>(serviceProvider.GetService<INameScope>())
NameScope = new WeakReference<INameScope?>(serviceProvider.GetService<INameScope>())
};
}
public IValueConverter Converter { get; set; }
public IValueConverter? Converter { get; set; }
public object ConverterParameter { get; set; }
public object? ConverterParameter { get; set; }
public string ElementName { get; set; }
public string? ElementName { get; set; }
public object FallbackValue { get; set; } = AvaloniaProperty.UnsetValue;
public object? FallbackValue { get; set; } = AvaloniaProperty.UnsetValue;
public BindingMode Mode { get; set; }
[ConstructorArgument("path")]
public string Path { get; set; }
public string Path { get; set; } = "";
public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
public object Source { get; set; }
public object? Source { get; set; }
public string StringFormat { get; set; }
public string? StringFormat { get; set; }
public RelativeSource RelativeSource { get; set; }
public RelativeSource? RelativeSource { get; set; }
public object TargetNullValue { get; set; } = AvaloniaProperty.UnsetValue;
public object? TargetNullValue { get; set; } = AvaloniaProperty.UnsetValue;
}
}

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs

@ -28,7 +28,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
[ConstructorArgument("mode")]
public RelativeSourceMode Mode { get; set; } = RelativeSourceMode.FindAncestor;
public Type AncestorType { get; set; }
public Type? AncestorType { get; set; }
public TreeType Tree { get; set; }

11
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs

@ -2,8 +2,6 @@
using Avalonia.Controls;
using Avalonia.Data.Core;
#nullable enable
namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class ResolveByNameExtension
@ -18,6 +16,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public object? ProvideValue(IServiceProvider serviceProvider)
{
var nameScope = serviceProvider.GetService<INameScope>();
if (nameScope is null)
return null;
var value = nameScope.FindAsync(Name);
@ -25,10 +26,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
return value.GetResult();
var provideValueTarget = serviceProvider.GetService<IProvideValueTarget>();
var target = provideValueTarget.TargetObject;
if (provideValueTarget.TargetProperty is IPropertyInfo property)
if (provideValueTarget?.TargetProperty is IPropertyInfo property)
{
var target = provideValueTarget.TargetObject;
value.OnCompleted(() => property.Set(target, value.GetResult()));
}
return AvaloniaProperty.UnsetValue;
}

34
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Markup.Data;
@ -8,8 +7,6 @@ using Avalonia.Markup.Xaml.Converters;
using Avalonia.Markup.Xaml.XamlIl.Runtime;
using Avalonia.Styling;
#nullable enable
namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class StaticResourceExtension
@ -25,7 +22,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public object? ResourceKey { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
public object? ProvideValue(IServiceProvider serviceProvider)
{
if (ResourceKey is not { } resourceKey)
{
@ -34,32 +31,37 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var stack = serviceProvider.GetService<IAvaloniaXamlIlParentStackProvider>();
var provideTarget = serviceProvider.GetService<IProvideValueTarget>();
var themeVariant = (provideTarget.TargetObject as IThemeVariantHost)?.ActualThemeVariant;
var targetObject = provideTarget?.TargetObject;
var targetProperty = provideTarget?.TargetProperty;
var themeVariant = (targetObject as IThemeVariantHost)?.ActualThemeVariant;
var targetType = provideTarget.TargetProperty switch
var targetType = targetProperty switch
{
AvaloniaProperty ap => ap.PropertyType,
PropertyInfo pi => pi.PropertyType,
_ => null,
_ => null
};
if (provideTarget.TargetObject is Setter { Property: not null } setter)
if (targetObject is Setter { Property: { } setterProperty })
{
targetType = setter.Property?.PropertyType;
targetType = setterProperty.PropertyType;
}
// Look upwards though the ambient context for IResourceNodes
// which might be able to give us the resource.
foreach (var parent in stack.Parents)
if (stack is not null)
{
if (parent is IResourceNode node && node.TryGetResource(resourceKey, themeVariant, out var value))
foreach (var parent in stack.Parents)
{
return ColorToBrushConverter.Convert(value, targetType);
if (parent is IResourceNode node && node.TryGetResource(resourceKey, themeVariant, out var value))
{
return ColorToBrushConverter.Convert(value, targetType);
}
}
}
if (provideTarget.TargetObject is Control target &&
provideTarget.TargetProperty is PropertyInfo property)
if (targetObject is Control target &&
targetProperty is PropertyInfo property)
{
// This is stored locally to avoid allocating closure in the outer scope.
var localTargetType = targetType;
@ -72,7 +74,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
throw new KeyNotFoundException($"Static resource '{resourceKey}' not found.");
}
private object GetValue(StyledElement control, Type? targetType)
private object? GetValue(StyledElement control, Type? targetType)
{
return ColorToBrushConverter.Convert(control.FindResource(ResourceKey!), targetType);
}

8
src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs

@ -5,7 +5,7 @@ namespace Avalonia.Markup.Xaml.Parsers
{
internal class PropertyParser
{
public static (string ns, string owner, string name) Parse(CharacterReader r)
public static (string? ns, string? owner, string name) Parse(CharacterReader r)
{
if (r.End)
{
@ -14,9 +14,9 @@ namespace Avalonia.Markup.Xaml.Parsers
var openParens = r.TakeIf('(');
bool closeParens = false;
string ns = null;
string owner = null;
string name = null;
string? ns = null;
string? owner = null;
string? name = null;
do
{

2
src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderConfiguration.cs

@ -2,8 +2,6 @@ using System.Reflection;
namespace Avalonia.Markup.Xaml;
#nullable enable
public class RuntimeXamlLoaderConfiguration
{
/// <summary>

3
src/Markup/Avalonia.Markup.Xaml/RuntimeXamlLoaderDocument.cs

@ -1,5 +1,4 @@
#nullable enable
using System;
using System;
using System.IO;
using System.Text;

3
src/Markup/Avalonia.Markup.Xaml/Styling/MergeResourceInclude.cs

@ -1,8 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
#nullable enable
namespace Avalonia.Markup.Xaml.Styling;

2
src/Markup/Avalonia.Markup.Xaml/Styling/ResourceInclude.cs

@ -3,8 +3,6 @@ using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Styling;
#nullable enable
namespace Avalonia.Markup.Xaml.Styling
{
/// <summary>

6
src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs

@ -4,8 +4,6 @@ using Avalonia.Controls;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
#nullable enable
namespace Avalonia.Markup.Xaml.Styling
{
/// <summary>
@ -65,11 +63,11 @@ namespace Avalonia.Markup.Xaml.Styling
_isLoading = false;
}
return _loaded?[0]!;
return _loaded[0];
}
}
bool IResourceNode.HasResources => Loaded?.HasResources ?? false;
bool IResourceNode.HasResources => Loaded.HasResources;
IReadOnlyList<IStyle> IStyle.Children => _loaded ?? Array.Empty<IStyle>();

6
src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs

@ -9,10 +9,10 @@ namespace Avalonia.Markup.Xaml.Templates
{
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
public Type TargetType { get; set; }
public Type? TargetType { get; set; }
public ControlTemplateResult Build(TemplatedControl control) => TemplateContent.Load(Content);
public ControlTemplateResult? Build(TemplatedControl control) => TemplateContent.Load(Content);
}
}

10
src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs

@ -8,13 +8,13 @@ namespace Avalonia.Markup.Xaml.Templates
public class DataTemplate : IRecyclingDataTemplate, ITypedDataTemplate
{
[DataType]
public Type DataType { get; set; }
public Type? DataType { get; set; }
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
public bool Match(object data)
public bool Match(object? data)
{
if (DataType == null)
{
@ -26,9 +26,9 @@ namespace Avalonia.Markup.Xaml.Templates
}
}
public Control Build(object data) => Build(data, null);
public Control? Build(object? data) => Build(data, null);
public Control Build(object data, Control existing)
public Control? Build(object? data, Control? existing)
{
return existing ?? TemplateContent.Load(Content)?.Control;
}

8
src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs

@ -4,14 +4,14 @@ using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.Templates
{
public class ItemsPanelTemplate : ITemplate<Panel>
public class ItemsPanelTemplate : ITemplate<Panel?>
{
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
public Panel Build() => (Panel)TemplateContent.Load(Content)?.Control;
public Panel? Build() => (Panel?)TemplateContent.Load(Content)?.Control;
object ITemplate.Build() => Build();
object? ITemplate.Build() => Build();
}
}

8
src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs

@ -4,14 +4,14 @@ using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.Templates
{
public class Template : ITemplate<Control>
public class Template : ITemplate<Control?>
{
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
public Control Build() => TemplateContent.Load(Content)?.Control;
public Control? Build() => TemplateContent.Load(Content)?.Control;
object ITemplate.Build() => Build();
object? ITemplate.Build() => Build();
}
}

17
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs

@ -3,14 +3,13 @@ using Avalonia.Controls.Templates;
namespace Avalonia.Markup.Xaml.Templates
{
public static class TemplateContent
{
public static ControlTemplateResult Load(object templateContent)
public static ControlTemplateResult? Load(object? templateContent)
{
if (templateContent is Func<IServiceProvider, object> direct)
if (templateContent is Func<IServiceProvider?, object?> direct)
{
return (ControlTemplateResult)direct(null);
return (ControlTemplateResult?)direct(null);
}
if (templateContent is null)
@ -18,18 +17,18 @@ namespace Avalonia.Markup.Xaml.Templates
return null;
}
throw new ArgumentException(nameof(templateContent));
throw new ArgumentException($"Unexpected content {templateContent.GetType()}", nameof(templateContent));
}
public static TemplateResult<T> Load<T>(object templateContent)
public static TemplateResult<T>? Load<T>(object? templateContent)
{
if (templateContent is Func<IServiceProvider, object> direct)
return (TemplateResult<T>)direct(null);
if (templateContent is Func<IServiceProvider?, object?> direct)
return (TemplateResult<T>?)direct(null);
if (templateContent is null)
return null;
throw new ArgumentException(nameof(templateContent));
throw new ArgumentException($"Unexpected content {templateContent.GetType()}", nameof(templateContent));
}
}
}

12
src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs

@ -13,16 +13,16 @@ namespace Avalonia.Markup.Xaml.Templates
public class TreeDataTemplate : ITreeDataTemplate, ITypedDataTemplate
{
[DataType]
public Type DataType { get; set; }
public Type? DataType { get; set; }
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
[AssignBinding]
public BindingBase ItemsSource { get; set; }
public BindingBase? ItemsSource { get; set; }
public bool Match(object data)
public bool Match(object? data)
{
if (DataType == null)
{
@ -35,7 +35,7 @@ namespace Avalonia.Markup.Xaml.Templates
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "If ItemsSource is a CompiledBinding, then path members will be preserver")]
public InstancedBinding ItemsSelector(object item)
public InstancedBinding? ItemsSelector(object item)
{
if (ItemsSource != null)
{
@ -52,7 +52,7 @@ namespace Avalonia.Markup.Xaml.Templates
return null;
}
public Control Build(object data)
public Control? Build(object? data)
{
var visualTreeForItem = TemplateContent.Load(Content)?.Control;
if (visualTreeForItem != null)

4
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs

@ -9,7 +9,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
public class AvaloniaXamlIlXmlNamespaceInfo
{
public string ClrNamespace { get; set; }
public string ClrAssemblyName { get; set; }
public string ClrNamespace { get; set; } = string.Empty;
public string ClrAssemblyName { get; set; } = string.Empty;
}
}

40
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -6,10 +6,7 @@ using System.Reflection;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
using Avalonia.Styling;
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedParameter.Global
@ -27,9 +24,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
public static Func<IServiceProvider, object> DeferredTransformationFactoryV2<T>(Func<IServiceProvider, object> builder,
IServiceProvider provider)
{
var resourceNodes = provider.GetService<IAvaloniaXamlIlParentStackProvider>().Parents
var resourceNodes = provider.GetRequiredService<IAvaloniaXamlIlParentStackProvider>().Parents
.OfType<IResourceNode>().ToList();
var rootObject = provider.GetService<IRootObjectProvider>().RootObject;
var rootObject = provider.GetRequiredService<IRootObjectProvider>().RootObject;
var parentScope = provider.GetService<INameScope>();
return sp =>
{
@ -44,17 +41,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
};
}
class DeferredParentServiceProvider :
private class DeferredParentServiceProvider :
IAvaloniaXamlIlParentStackProvider,
IServiceProvider,
IRootObjectProvider,
IAvaloniaXamlIlControlTemplateProvider
{
private readonly IServiceProvider _parentProvider;
private readonly List<IResourceNode> _parentResourceNodes;
private readonly IServiceProvider? _parentProvider;
private readonly List<IResourceNode>? _parentResourceNodes;
private readonly INameScope _nameScope;
public DeferredParentServiceProvider(IServiceProvider parentProvider, List<IResourceNode> parentResourceNodes,
public DeferredParentServiceProvider(IServiceProvider? parentProvider, List<IResourceNode>? parentResourceNodes,
object rootObject, INameScope nameScope)
{
_parentProvider = parentProvider;
@ -73,7 +70,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
yield return p;
}
public object GetService(Type serviceType)
public object? GetService(Type serviceType)
{
if (serviceType == typeof(INameScope))
return _nameScope;
@ -115,25 +112,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
public static IServiceProvider CreateInnerServiceProviderV1(IServiceProvider compiled)
=> new InnerServiceProvider(compiled);
class InnerServiceProvider : IServiceProvider
private class InnerServiceProvider : IServiceProvider
{
private readonly IServiceProvider _compiledProvider;
private XamlTypeResolver _resolver;
private XamlTypeResolver? _resolver;
public InnerServiceProvider(IServiceProvider compiledProvider)
{
_compiledProvider = compiledProvider;
}
public object GetService(Type serviceType)
public object? GetService(Type serviceType)
{
if (serviceType == typeof(IXamlTypeResolver))
return _resolver ?? (_resolver = new XamlTypeResolver(
_compiledProvider.GetService<IAvaloniaXamlIlXmlNamespaceInfoProvider>()));
return _resolver ??= new XamlTypeResolver(
_compiledProvider.GetRequiredService<IAvaloniaXamlIlXmlNamespaceInfoProvider>());
return null;
}
}
class XamlTypeResolver : IXamlTypeResolver
private class XamlTypeResolver : IXamlTypeResolver
{
private readonly IAvaloniaXamlIlXmlNamespaceInfoProvider _nsInfo;
@ -148,7 +145,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
var sp = qualifiedTypeName.Split(new[] {':'}, 2);
var (ns, name) = sp.Length == 1 ? ("", qualifiedTypeName) : (sp[0], sp[1]);
var namespaces = _nsInfo.XmlNamespaces;
var dic = (Dictionary<string, IReadOnlyList<AvaloniaXamlIlXmlNamespaceInfo>>)namespaces;
if (!namespaces.TryGetValue(ns, out var lst))
throw new ArgumentException("Unable to resolve namespace for type " + qualifiedTypeName);
foreach (var entry in lst)
@ -177,20 +173,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
}
#line default
class RootServiceProvider : IServiceProvider
private class RootServiceProvider : IServiceProvider
{
private readonly INameScope _nameScope;
private readonly IServiceProvider _parentServiceProvider;
private readonly IRuntimePlatform _runtimePlatform;
private readonly IServiceProvider? _parentServiceProvider;
private readonly IRuntimePlatform? _runtimePlatform;
public RootServiceProvider(INameScope nameScope, IServiceProvider parentServiceProvider)
public RootServiceProvider(INameScope nameScope, IServiceProvider? parentServiceProvider)
{
_nameScope = nameScope;
_parentServiceProvider = parentServiceProvider;
_runtimePlatform = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
}
public object GetService(Type serviceType)
public object? GetService(Type serviceType)
{
if (serviceType == typeof(INameScope))
return _nameScope;

3
src/Markup/Avalonia.Markup/Data/Binding.cs

@ -16,7 +16,6 @@ namespace Avalonia.Data
/// Initializes a new instance of the <see cref="Binding"/> class.
/// </summary>
public Binding()
:base()
{
}
@ -54,7 +53,7 @@ namespace Avalonia.Data
/// <summary>
/// Gets or sets a function used to resolve types from names in the binding path.
/// </summary>
public Func<string, string, Type>? TypeResolver { get; set; }
public Func<string?, string, Type>? TypeResolver { get; set; }
private protected override ExpressionObserver CreateExpressionObserver(AvaloniaObject target, AvaloniaProperty? targetProperty, object? anchor, bool enableDataValidation)
{

5
src/Markup/Avalonia.Markup/Data/BindingBase.cs

@ -7,7 +7,6 @@ using Avalonia.LogicalTree;
using Avalonia.Reactive;
using Avalonia.VisualTree;
namespace Avalonia.Data
{
public abstract class BindingBase : IBinding
@ -68,7 +67,7 @@ namespace Avalonia.Data
public WeakReference? DefaultAnchor { get; set; }
public WeakReference<INameScope>? NameScope { get; set; }
public WeakReference<INameScope?>? NameScope { get; set; }
private protected abstract ExpressionObserver CreateExpressionObserver(
AvaloniaObject target,
@ -169,7 +168,7 @@ namespace Avalonia.Data
{
_ = target ?? throw new ArgumentNullException(nameof(target));
if (NameScope is null || !NameScope.TryGetTarget(out var scope) || scope is null)
if (NameScope is null || !NameScope.TryGetTarget(out var scope))
throw new InvalidOperationException("Name scope is null or was already collected");
var result = new ExpressionObserver(
NameScopeLocator.Track(scope, elementName),

27
src/Markup/Avalonia.Markup/Data/TemplateBinding.cs

@ -16,7 +16,7 @@ namespace Avalonia.Data
ISetterValue
{
private bool _isSetterValue;
private StyledElement _target = default!;
private StyledElement? _target;
private Type? _targetType;
private bool _hasProducedValue;
@ -42,7 +42,7 @@ namespace Avalonia.Data
//
// If the binding appears in a `Setter`, then make a clone and instantiate that because
// because the setter can outlive the control and cause a leak.
if (_target == null && !_isSetterValue)
if (_target is null && !_isSetterValue)
{
_target = (StyledElement)target;
_targetType = targetProperty?.PropertyType;
@ -93,9 +93,9 @@ namespace Avalonia.Data
void IObserver<object?>.OnNext(object? value)
{
if (_target.TemplatedParent is AvaloniaObject templatedParent && Property != null)
if (_target?.TemplatedParent is { } templatedParent && Property is not null)
{
if (Converter != null)
if (Converter is not null)
{
value = Converter.ConvertBack(
value,
@ -114,24 +114,31 @@ namespace Avalonia.Data
protected override void Subscribed()
{
TemplatedParentChanged();
_target.PropertyChanged += TargetPropertyChanged;
if (_target is not null)
{
_target.PropertyChanged += TargetPropertyChanged;
}
}
protected override void Unsubscribed()
{
if (_target.TemplatedParent is AvaloniaObject templatedParent)
if (_target?.TemplatedParent is { } templatedParent)
{
templatedParent.PropertyChanged -= TemplatedParentPropertyChanged;
}
_target.PropertyChanged -= TargetPropertyChanged;
if (_target is not null)
{
_target.PropertyChanged -= TargetPropertyChanged;
}
}
private void PublishValue()
{
if (_target.TemplatedParent is AvaloniaObject templatedParent)
if (_target?.TemplatedParent is { } templatedParent)
{
var value = Property != null ?
var value = Property is not null ?
templatedParent.GetValue(Property) :
_target.TemplatedParent;
@ -152,7 +159,7 @@ namespace Avalonia.Data
private void TemplatedParentChanged()
{
if (_target.TemplatedParent is AvaloniaObject templatedParent)
if (_target?.TemplatedParent is { } templatedParent)
{
templatedParent.PropertyChanged += TemplatedParentPropertyChanged;
}

9
src/Markup/Avalonia.Markup/Markup/Data/DelayedBinding.cs

@ -20,8 +20,7 @@ namespace Avalonia.Markup.Data
/// </remarks>
public static class DelayedBinding
{
private static ConditionalWeakTable<StyledElement, List<Entry>> _entries =
new ConditionalWeakTable<StyledElement, List<Entry>>();
private static readonly ConditionalWeakTable<StyledElement, List<Entry>> _entries = new();
/// <summary>
/// Adds a delayed binding to a control.
@ -57,7 +56,7 @@ namespace Avalonia.Markup.Data
/// <param name="target">The control.</param>
/// <param name="property">The property on the control to bind to.</param>
/// <param name="value">A function which returns the value.</param>
public static void Add(StyledElement target, PropertyInfo property, Func<StyledElement, object> value)
public static void Add(StyledElement target, PropertyInfo property, Func<StyledElement, object?> value)
{
if (target.IsInitialized)
{
@ -126,14 +125,14 @@ namespace Avalonia.Markup.Data
private class ClrPropertyValueEntry : Entry
{
public ClrPropertyValueEntry(PropertyInfo property, Func<StyledElement, object> value)
public ClrPropertyValueEntry(PropertyInfo property, Func<StyledElement, object?> value)
{
Property = property;
Value = value;
}
public PropertyInfo Property { get; }
public Func<StyledElement, object> Value { get; }
public Func<StyledElement, object?> Value { get; }
public override void Apply(StyledElement control)
{

6
src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs

@ -6,8 +6,6 @@ using Avalonia.Utilities;
using System;
using System.Collections.Generic;
#nullable enable
namespace Avalonia.Markup.Parsers
{
internal enum SourceMode
@ -201,8 +199,8 @@ namespace Avalonia.Markup.Parsers
nodes.Add(new AttachedPropertyNameNode
{
Namespace = ns.ToString(),
TypeName = owner.ToString(),
Namespace = ns,
TypeName = owner,
PropertyName = name.ToString()
});
return State.AfterMember;

8
src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionObserverBuilder.cs

@ -9,7 +9,7 @@ namespace Avalonia.Markup.Parsers
internal static class ExpressionObserverBuilder
{
[RequiresUnreferencedCode(TrimmingMessages.ReflectionBindingRequiresUnreferencedCodeMessage)]
internal static (ExpressionNode Node, SourceMode Mode) Parse(string expression, bool enableValidation = false, Func<string, string, Type>? typeResolver = null,
internal static (ExpressionNode Node, SourceMode Mode) Parse(string expression, bool enableValidation = false, Func<string?, string, Type>? typeResolver = null,
INameScope? nameScope = null)
{
if (string.IsNullOrWhiteSpace(expression))
@ -35,7 +35,7 @@ namespace Avalonia.Markup.Parsers
string expression,
bool enableDataValidation = false,
string? description = null,
Func<string, string, Type>? typeResolver = null)
Func<string?, string, Type>? typeResolver = null)
{
return new ExpressionObserver(
root,
@ -49,7 +49,7 @@ namespace Avalonia.Markup.Parsers
string expression,
bool enableDataValidation = false,
string? description = null,
Func<string, string, Type>? typeResolver = null)
Func<string?, string, Type>? typeResolver = null)
{
_ = rootObservable ?? throw new ArgumentNullException(nameof(rootObservable));
@ -66,7 +66,7 @@ namespace Avalonia.Markup.Parsers
IObservable<ValueTuple> update,
bool enableDataValidation = false,
string? description = null,
Func<string, string, Type>? typeResolver = null)
Func<string?, string, Type>? typeResolver = null)
{
_ = rootGetter ?? throw new ArgumentNullException(nameof(rootGetter));

12
src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs

@ -2,8 +2,6 @@ using Avalonia.Data.Core;
using Avalonia.Markup.Parsers.Nodes;
using Avalonia.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using System.Diagnostics.CodeAnalysis;
@ -18,7 +16,7 @@ namespace Avalonia.Markup.Parsers
private readonly Func<string, string, Type>? _typeResolver;
private readonly INameScope? _nameScope;
public ExpressionParser(bool enableValidation, Func<string, string, Type>? typeResolver, INameScope? nameScope)
public ExpressionParser(bool enableValidation, Func<string?, string, Type>? typeResolver, INameScope? nameScope)
{
_typeResolver = typeResolver;
_nameScope = nameScope;
@ -37,13 +35,13 @@ namespace Avalonia.Markup.Parsers
ExpressionNode? nextNode = null;
switch (astNode)
{
case BindingExpressionGrammar.EmptyExpressionNode _:
case BindingExpressionGrammar.EmptyExpressionNode:
nextNode = new EmptyExpressionNode();
break;
case BindingExpressionGrammar.NotNode _:
case BindingExpressionGrammar.NotNode:
nextNode = new LogicalNotNode();
break;
case BindingExpressionGrammar.StreamNode _:
case BindingExpressionGrammar.StreamNode:
nextNode = new StreamNode();
break;
case BindingExpressionGrammar.PropertyNameNode propName:
@ -55,7 +53,7 @@ namespace Avalonia.Markup.Parsers
case BindingExpressionGrammar.AttachedPropertyNameNode attachedProp:
nextNode = ParseAttachedProperty(attachedProp);
break;
case BindingExpressionGrammar.SelfNode _:
case BindingExpressionGrammar.SelfNode:
nextNode = new SelfNode();
break;
case BindingExpressionGrammar.AncestorNode ancestor:

6
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@ -4,9 +4,7 @@ using System.Linq;
using Avalonia.Data.Core;
using Avalonia.Utilities;
#nullable enable
// Don't need to override GetHashCode as the ISyntax objects will not be stored in a hash; the
// Don't need to override GetHashCode as the ISyntax objects will not be stored in a hash; the
// only reason they have overridden Equals methods is for unit testing.
#pragma warning disable 659
@ -642,7 +640,7 @@ namespace Avalonia.Markup.Parsers
{
public override bool Equals(object? obj)
{
return obj is CommaSyntax or;
return obj is CommaSyntax;
}
}

11
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

@ -2,6 +2,7 @@ using System;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Markup.Xaml.Templates;
@ -308,6 +309,16 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Equal("Foo", foo.Name);
Assert.Equal("Bar", bar.Name);
}
[Fact]
public void ControlTemplate_Can_Be_Empty()
{
var xaml = "<ControlTemplate xmlns='https://github.com/avaloniaui' />";
var template = AvaloniaRuntimeXamlLoader.Parse<ControlTemplate>(xaml);
var templateResult = template.Build(new TemplatedControl());
Assert.Null(templateResult);
}
}
public class ListBoxHierarchyLine : Panel
{

Loading…
Cancel
Save