diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs new file mode 100644 index 0000000000..117f7768f1 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs @@ -0,0 +1,33 @@ +// 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 Perspex.Markup.Xaml.Binding; +using OmniXaml; +using OmniXaml.Typing; +using System.Reflection; + +namespace Perspex.Markup.Xaml.Context +{ + public class PerspexAttachableXamlMember : AttachableXamlMember + { + public PerspexAttachableXamlMember(string name, + XamlType owner, + MethodInfo getter, + MethodInfo setter, + IXamlTypeRepository xamlTypeRepository, + ITypeFeatureProvider featureProvider) + : base(name, getter, setter, xamlTypeRepository, featureProvider) + { + } + + protected override IXamlMemberValuePlugin LookupXamlMemberValueConnector() + { + return new PerspexXamlMemberValuePlugin(this); + } + + public override string ToString() + { + return "Perspex Attachable XAML Member " + base.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs index fd7a786649..36e1d03ea8 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Reactive.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using Glass; using OmniXaml.ObjectAssembler; using OmniXaml.Typing; @@ -16,9 +17,9 @@ namespace Perspex.Markup.Xaml.Context { public class PerspexXamlMemberValuePlugin : MemberValuePlugin { - private readonly XamlMember _xamlMember; + private readonly MutableXamlMember _xamlMember; - public PerspexXamlMemberValuePlugin(XamlMember xamlMember) + public PerspexXamlMemberValuePlugin(MutableXamlMember xamlMember) : base(xamlMember) { _xamlMember = xamlMember; @@ -73,6 +74,7 @@ namespace Perspex.Markup.Xaml.Context else { var perspexObject = instance as PerspexObject; + var attached = _xamlMember as PerspexAttachableXamlMember; if (perspexObject == null) { @@ -80,13 +82,31 @@ namespace Perspex.Markup.Xaml.Context $"Cannot bind to an object of type '{instance.GetType()}"); } - var property = perspexObject.GetRegisteredProperties() - .FirstOrDefault(x => x.Name == _xamlMember.Name); + PerspexProperty property; + string propertyName; + + if (attached == null) + { + propertyName = _xamlMember.Name; + property = perspexObject.GetRegisteredProperties() + .FirstOrDefault(x => x.Name == propertyName); + } + else + { + // Ensure the OwnerType's static ctor has been run. + RuntimeHelpers.RunClassConstructor(attached.DeclaringType.UnderlyingType.TypeHandle); + + propertyName = attached.DeclaringType.UnderlyingType.Name + '.' + _xamlMember.Name; + + property = perspexObject.GetRegisteredProperties() + .Where(x => x.IsAttached && x.OwnerType == attached.DeclaringType.UnderlyingType) + .FirstOrDefault(x => x.Name == _xamlMember.Name); + } if (property == null) { throw new InvalidOperationException( - $"Cannot find '{_xamlMember.Name}' on '{instance.GetType()}"); + $"Cannot find '{propertyName}' on '{instance.GetType()}"); } var binding = new XamlBinding diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs index 0d1fb218b1..dc6b7398f4 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Reflection; using OmniXaml; using OmniXaml.Typing; using Perspex.Markup.Xaml.Binding; @@ -22,6 +23,14 @@ namespace Perspex.Markup.Xaml.Context return new PerspexXamlMember(name, this, TypeRepository, FeatureProvider); } + protected override AttachableXamlMember LookupAttachableMember(string name) + { + // OmniXAML seems to require a getter and setter even though we don't use them. + var getter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Get" + name); + var setter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Set" + name); + return new PerspexAttachableXamlMember(name, this, getter, setter, TypeRepository, FeatureProvider); + } + public override string ToString() { return "Perspex XAML Type " + base.ToString(); diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index 987b630907..d34c97c50f 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -42,6 +42,7 @@ +