Browse Source

Compiled path support for cast

pull/5038/head
Andrey Kunchev 6 years ago
parent
commit
4563c6cd24
  1. 34
      src/Avalonia.Base/Data/Core/TypeCastNode.cs
  2. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  3. 51
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
  4. 18
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs

34
src/Avalonia.Base/Data/Core/TypeCastNode.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Data.Core
{
public class TypeCastNode : ExpressionNode
{
public override string Description => $"as {TargetType.FullName}";
public Type TargetType { get; }
public TypeCastNode(Type type)
{
TargetType = type;
}
protected virtual object Cast(object value)
{
return TargetType.IsInstanceOfType(value) ? value : null;
}
protected override void StartListeningCore(WeakReference<object> reference)
{
if (reference.TryGetTarget(out object target))
{
target = Cast(target);
reference = target == null ? NullReference : new WeakReference<object>(target);
}
base.StartListeningCore(reference);
}
}
}

1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -23,6 +23,7 @@
<Compile Include="MarkupExtensions\CompiledBindings\ObservableStreamPlugin.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorFactory.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorPlugin.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\StrongTypeCastNode.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\TaskStreamPlugin.cs" />
<Compile Include="MarkupExtensions\DynamicResourceExtension.cs" />
<Compile Include="MarkupExtensions\ResolveByNameExtension.cs" />

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

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
@ -53,6 +54,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
case IStronglyTypedStreamElement stream:
node = new StreamNode(stream.CreatePlugin());
break;
case ITypeCastElement typeCast:
node = new StrongTypeCastNode(typeCast.Type, typeCast.Cast);
break;
default:
throw new InvalidOperationException($"Unknown binding path element type {element.GetType().FullName}");
}
@ -66,6 +70,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal SourceMode SourceMode => _elements.Count > 0 && _elements[0] is IControlSourceBindingPathElement ? SourceMode.Control : SourceMode.Data;
internal object RawSource { get; }
public override string ToString()
=> string.Concat(_elements.Select(e => e.ToString()));
}
public class CompiledBindingPathBuilder
@ -126,6 +133,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
public CompiledBindingPathBuilder TypeCast<T>()
{
_elements.Add(new TypeCastPathElement<T>());
return this;
}
public CompiledBindingPathBuilder SetRawSource(object rawSource)
{
_rawSource = rawSource;
@ -157,6 +170,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public IPropertyInfo Property { get; }
public Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
public override string ToString()
=> $".{Property.Name}";
}
internal interface IStronglyTypedStreamElement : ICompiledBindingPathElement
@ -164,6 +180,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
IStreamPlugin CreatePlugin();
}
internal interface ITypeCastElement : ICompiledBindingPathElement
{
Type Type { get; }
Func<object, object> Cast { get; }
}
internal class TaskStreamPathElement<T> : IStronglyTypedStreamElement
{
public static readonly TaskStreamPathElement<T> Instance = new TaskStreamPathElement<T>();
@ -181,6 +204,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class SelfPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
{
public static readonly SelfPathElement Instance = new SelfPathElement();
public override string ToString()
=> "$self";
}
internal class AncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@ -193,6 +219,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public Type AncestorType { get; }
public int Level { get; }
public override string ToString()
=> $"$parent[{AncestorType?.Name},{Level}]";
}
internal class VisualAncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@ -217,6 +246,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public INameScope NameScope { get; }
public string Name { get; }
public override string ToString()
=> $"#{Name}";
}
internal class ArrayElementPathElement : ICompiledBindingPathElement
@ -229,5 +261,24 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public int[] Indices { get; }
public Type ElementType { get; }
public override string ToString()
=> $"[{string.Join(",", Indices)}]";
}
internal class TypeCastPathElement<T> : ITypeCastElement
{
private static object TryCast(object obj)
{
if (obj is T result)
return result;
return null;
}
public Type Type => typeof(T);
public Func<object, object> Cast => TryCast;
public override string ToString()
=> $"({Type.FullName})";
}
}

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

@ -0,0 +1,18 @@
using System;
using Avalonia.Data.Core;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
public class StrongTypeCastNode : TypeCastNode
{
private Func<object, object> _cast;
public StrongTypeCastNode(Type type, Func<object, object> cast) : base(type)
{
_cast = cast;
}
protected override object Cast(object value)
=> _cast(value);
}
}
Loading…
Cancel
Save