File: System\Windows\Markup\Baml2006\WpfXamlMember.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Xaml;
using System.Xaml.Schema;
 
namespace System.Windows.Baml2006
{
    internal class WpfXamlMember : XamlMember, System.Windows.Markup.IProvideValueTarget
    {
        [Flags]
        private enum BoolMemberBits
        {
            UseV3Rules = 0x0001,
            BamlMember = 0x0002,
            UnderlyingMemberIsKnown = 0x0004,
            ApplyGetterFallback = 0x0008,
        }
 
        public WpfXamlMember(DependencyProperty dp, bool isAttachable)
            : base(dp.Name, 
                   System.Windows.Markup.XamlReader.BamlSharedSchemaContext.GetXamlType(dp.OwnerType),
                   isAttachable)
        {
            DependencyProperty = dp;
            _useV3Rules = true;
            _isBamlMember = true;
            _underlyingMemberIsKnown = false;
        }
 
        public WpfXamlMember(RoutedEvent re, bool isAttachable)
            : base(re.Name,
                   System.Windows.Markup.XamlReader.BamlSharedSchemaContext.GetXamlType(re.OwnerType),
                   isAttachable)
        {
            RoutedEvent = re;
            _useV3Rules = true;
            _isBamlMember = true;
            _underlyingMemberIsKnown = false;
        }
 
        public WpfXamlMember(DependencyProperty dp,
            MethodInfo getter,
            MethodInfo setter,
            XamlSchemaContext schemaContext,
            bool useV3Rules)
            : base(dp.Name, getter, setter, schemaContext)
        {
            DependencyProperty = dp;
            _useV3Rules = useV3Rules;
            _underlyingMemberIsKnown = true;
        }
 
        public WpfXamlMember(DependencyProperty dp,
            PropertyInfo property,
            XamlSchemaContext schemaContext,
            bool useV3Rules)
            : base (property, schemaContext)
        {
            DependencyProperty = dp;
            _useV3Rules = useV3Rules;
            _underlyingMemberIsKnown = true;
        }
 
        public WpfXamlMember(RoutedEvent re,
            MethodInfo setter,
            XamlSchemaContext schemaContext,
            bool useV3Rules)
            : base(re.Name, setter, schemaContext)
        {
            RoutedEvent = re;
            _useV3Rules = useV3Rules;
            _underlyingMemberIsKnown = true;
        }
 
        public WpfXamlMember(RoutedEvent re,
            EventInfo eventInfo,
            XamlSchemaContext schemaContext,
            bool useV3Rules)
            : base(eventInfo, schemaContext)
        {
            RoutedEvent = re;
            _useV3Rules = useV3Rules;
            _underlyingMemberIsKnown = true;
        }
 
        // Protected ctor that is called by WpfKnownMember for known properties that aren't DPs
        protected WpfXamlMember(string name, XamlType declaringType, bool isAttachable)
            : base(name, declaringType, isAttachable)
        {
            _useV3Rules = true;
            _isBamlMember = true;
            _underlyingMemberIsKnown = false;
        }
 
        public DependencyProperty DependencyProperty { get; set; }
        public RoutedEvent RoutedEvent { get; set; }
 
        internal bool ApplyGetterFallback
        {
            get { return WpfXamlType.GetFlag(ref _bitField, (byte)BoolMemberBits.ApplyGetterFallback); }
            private set { WpfXamlType.SetFlag(ref _bitField, (byte)BoolMemberBits.ApplyGetterFallback, value); }
        }
 
        // v3 parser had a fallback for retrieved DP content properties. If the DP was null, it would
        // call the CLR property getter, in case the property was lazily initialized. If necessary,
        // we return a version of this property with the fallback logic.
        internal WpfXamlMember AsContentProperty
        {
            get
            {
                if (_asContentProperty == null)
                {
                    _asContentProperty = GetAsContentProperty();
                }
                return _asContentProperty;
            }
        }
 
        protected virtual WpfXamlMember GetAsContentProperty()
        {
            if (DependencyProperty == null)
            {
                // Not a DP, no fallback needed
                return this;
            }
            Debug.Assert(!IsAttachable && !IsEvent);
            WpfXamlMember result = null;
            if (_underlyingMemberIsKnown)
            {
                PropertyInfo underlyingProperty = UnderlyingMember as PropertyInfo;
                if (underlyingProperty == null)
                {
                    // No underlying CLR property, no fallback needed
                    return this;
                }
                result = new WpfXamlMember(DependencyProperty, underlyingProperty, DeclaringType.SchemaContext, _useV3Rules);
            }
            else
            {
                result = new WpfXamlMember(DependencyProperty, false /*isAttachable*/);
            }
            result.ApplyGetterFallback = true;
            return result;
        }
 
        protected override XamlType LookupType()
        {
            if (DependencyProperty != null)
            {
                if (_isBamlMember)
                {
                    return System.Windows.Markup.XamlReader.BamlSharedSchemaContext.GetXamlType(DependencyProperty.PropertyType);
                }
                else
                {
                    return System.Windows.Markup.XamlReader.GetWpfSchemaContext().GetXamlType(DependencyProperty.PropertyType);
                }
            }
            else if (RoutedEvent != null)
            {
                if (_isBamlMember)
                {
                    return System.Windows.Markup.XamlReader.BamlSharedSchemaContext.GetXamlType(RoutedEvent.HandlerType);
                }
                else
                {
                    return System.Windows.Markup.XamlReader.GetWpfSchemaContext().GetXamlType(RoutedEvent.HandlerType);
                }
            }
            else
            {
                return base.LookupType();
            }
        }
 
        protected override MemberInfo LookupUnderlyingMember()
        {
            MemberInfo member = base.LookupUnderlyingMember();
            if (member == null)
            {
                if (BaseUnderlyingMember != null)
                {
                    member = BaseUnderlyingMember.UnderlyingMember;
                }
            }
            _underlyingMemberIsKnown = true;
            return member;
        }
 
        protected override MethodInfo LookupUnderlyingSetter()
        {
            // Want to look up the base's UnderlyingSetter in case it's already there
            MethodInfo setter = base.LookupUnderlyingSetter();
            if (setter == null)
            {
                if (BaseUnderlyingMember != null)
                {
                    setter = BaseUnderlyingMember.Invoker.UnderlyingSetter;
                }
            }
            _underlyingMemberIsKnown = true;
            return setter;
        }
 
        protected override MethodInfo LookupUnderlyingGetter()
        {
            // Want to look up the base's UnderlyingSetter in case it's already there
            MethodInfo getter = base.LookupUnderlyingGetter();
            if (getter == null)
            {
                if (BaseUnderlyingMember != null)
                {
                    getter = BaseUnderlyingMember.Invoker.UnderlyingGetter;
                }
            }
            _underlyingMemberIsKnown = true;
            return getter;
        }
 
        protected override bool LookupIsReadOnly()
        {
            if (DependencyProperty != null)
            {
                return DependencyProperty.ReadOnly;
            }
            return base.LookupIsReadOnly();
        }
 
        protected override bool LookupIsEvent()
        {
            if (RoutedEvent != null)
            {
                return true;
            }
            return false;
        }
 
        protected override XamlMemberInvoker LookupInvoker()
        {
            return new WpfMemberInvoker(this);
        }
 
        protected override bool LookupIsUnknown()
        {
            return false;
        }
 
        // The Markup compiler doesn't support XamlDeferringLoader so we don't need to look it up in BAML scenarios.
        protected override XamlValueConverter<XamlDeferringLoader>  LookupDeferringLoader()
        {
            if (_useV3Rules)
            {
                return null;
            }
            else
            {
                return base.LookupDeferringLoader();
            }
        }
 
        private bool _useV3Rules
        {
            get { return WpfXamlType.GetFlag(ref _bitField, (byte)BoolMemberBits.UseV3Rules); }
            set { WpfXamlType.SetFlag(ref _bitField, (byte)BoolMemberBits.UseV3Rules, value); }
        }
        private bool _isBamlMember
        {
            get { return WpfXamlType.GetFlag(ref _bitField, (byte)BoolMemberBits.BamlMember); }
            set { WpfXamlType.SetFlag(ref _bitField, (byte)BoolMemberBits.BamlMember, value); }
        }
        private bool _underlyingMemberIsKnown
        {
            get { return WpfXamlType.GetFlag(ref _bitField, (byte)BoolMemberBits.UnderlyingMemberIsKnown); }
            set { WpfXamlType.SetFlag(ref _bitField, (byte)BoolMemberBits.UnderlyingMemberIsKnown, value); }
        }
 
        #region IProvideValueTarget Members
 
        object System.Windows.Markup.IProvideValueTarget.TargetObject
        {
            get { throw new NotSupportedException(); }
        }
 
        object System.Windows.Markup.IProvideValueTarget.TargetProperty
        {
            get
            {
                if (DependencyProperty != null)
                {
                    return DependencyProperty;
                }
                else
                {
                    return UnderlyingMember;
                }
            }
        }
 
        #endregion
 
        private XamlMember BaseUnderlyingMember
        {
            get
            {
                if (_baseUnderlyingMember == null)
                {
                    WpfXamlType wpfXType = DeclaringType as WpfXamlType;
 
                    _baseUnderlyingMember = wpfXType.FindBaseXamlMember(Name, IsAttachable);
 
                    if (_baseUnderlyingMember == null)
                    {
                        // Find the attached or regular property
                        _baseUnderlyingMember = wpfXType.FindBaseXamlMember(Name, !IsAttachable);
                    }
                }
 
                return _baseUnderlyingMember;
            }
        }
 
        private byte _bitField;
        private XamlMember _baseUnderlyingMember;
        private WpfXamlMember _asContentProperty;
    } 
}