File: System\Windows\Condition.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.Windows.Markup;
using System.ComponentModel;
using System.Windows.Data;
using System.Globalization;
 
namespace System.Windows
{
    /// <summary>
    ///     Condition for a multiple property or data trigger
    /// </summary>
    [XamlSetMarkupExtensionAttribute("ReceiveMarkupExtension")]
    [XamlSetTypeConverterAttribute("ReceiveTypeConverter")] 
    public sealed class Condition : ISupportInitialize
    {
        /// <summary>
        ///     Constructor with no property reference nor value
        /// </summary>
        public Condition()
        {
            _property = null;
            _binding = null;
        }
 
        /// <summary>
        ///     Constructor for creating a Condition
        /// </summary>
        public Condition( DependencyProperty conditionProperty, object conditionValue ) :
            this(conditionProperty, conditionValue, null)
        {
            // Call Forwarded
        }
 
        /// <summary>
        ///     Constructor for creating a Condition with the given property
        /// and value instead of creating an empty one and setting values later.
        /// </summary>
        /// <remarks>
        ///     This constructor does parameter validation, which before doesn't
        /// happen until Seal() is called.  We can do it here because we get
        /// both at the same time.
        /// </remarks>
        public Condition( DependencyProperty conditionProperty, object conditionValue, string sourceName )
        {
            ArgumentNullException.ThrowIfNull(conditionProperty);
 
            if (!conditionProperty.IsValidValue(conditionValue))
            {
                throw new ArgumentException(SR.Format(SR.InvalidPropertyValue, conditionValue, conditionProperty.Name));
            }
 
            _property = conditionProperty;
            Value    = conditionValue;
            _sourceName = sourceName;
        }
 
        /// <summary>
        ///     Constructor for creating a Condition with the given binding declaration.
        /// and value.
        /// </summary>
        public Condition( BindingBase binding, object conditionValue )
        {
            ArgumentNullException.ThrowIfNull(binding);
 
            Binding = binding;
            Value  = conditionValue;
        }
 
        /// <summary>
        ///     DepedencyProperty of the conditional
        /// </summary>
        [Ambient]
        [DefaultValue(null)]
        public DependencyProperty Property
        {
            get { return _property; }
            set
            {
                if (_sealed)
                {
                    throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "Condition"));
                }
 
                if (_binding != null)
                {
                    throw new InvalidOperationException(SR.ConditionCannotUseBothPropertyAndBinding);
                }
 
                _property = value;
            }
        }
 
        /// <summary>
        ///     Binding of the conditional
        /// </summary>
        [DefaultValue(null)]
        public BindingBase Binding
        {
            get { return _binding; }
            set
            {
                if (_sealed)
                {
                    throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "Condition"));
                }
 
                if(_property != null)
                {
                    throw new InvalidOperationException(SR.ConditionCannotUseBothPropertyAndBinding);
                }
 
                _binding = value;
            }
        }
 
        /// <summary>
        ///     Value of the condition (equality check)
        /// </summary>
        [TypeConverter(typeof(System.Windows.Markup.SetterTriggerConditionValueConverter))]
        public object Value
        {
            get { return _value; }
            set
            {
                if (_sealed)
                {
                    throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "Condition"));
                }
 
                if (value is MarkupExtension)
                {
                    throw new ArgumentException(SR.Format(SR.ConditionValueOfMarkupExtensionNotSupported,
                                                       value.GetType().Name));
                }
 
                if(value is Expression)
                {
                    throw new ArgumentException(SR.ConditionValueOfExpressionNotSupported);
                }
 
                _value = value;
            }
        }
 
        /// <summary>
        /// The x:Name of the object whose property shall
        /// trigger the associated setters to be applied.
        /// If null, then this is the object being Styled
        /// and not anything under its Template Tree.
        /// </summary>
        [DefaultValue(null)]
        public string SourceName
        {
            get
            {
                return _sourceName;
            }
            set
            {
                if(_sealed)
                {
                    throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "Condition"));
                }
 
                _sourceName = value;
            }
        }
 
        /// <summary>
        ///     Seal the condition so that it can no longer be modified
        /// </summary>
        internal void Seal(ValueLookupType type)
        {
            if (_sealed)
            {
                return;
            }
 
            _sealed = true;
 
            // Ensure valid condition
            if (_property != null && _binding != null)
                throw new InvalidOperationException(SR.ConditionCannotUseBothPropertyAndBinding);
 
            switch (type)
            {
                case ValueLookupType.Trigger:
                case ValueLookupType.PropertyTriggerResource:
                    if (_property == null)
                    {
                        throw new InvalidOperationException(SR.Format(SR.NullPropertyIllegal, "Property"));
                    }
 
                    if (!_property.IsValidValue(_value))
                    {
                        throw new InvalidOperationException(SR.Format(SR.InvalidPropertyValue, _value, _property.Name));
                    }
                    break;
 
                case ValueLookupType.DataTrigger:
                case ValueLookupType.DataTriggerResource:
                    if (_binding == null)
                    {
                        throw new InvalidOperationException(SR.Format(SR.NullPropertyIllegal, "Binding"));
                    }
                    break;
 
                default:
                    throw new InvalidOperationException(SR.Format(SR.UnexpectedValueTypeForCondition, type));
            }
 
            // Freeze the condition value
            StyleHelper.SealIfSealable(_value);
        }
 
 
        #region ISupportInitialize Members
 
        void ISupportInitialize.BeginInit()
        {
        }
 
        void ISupportInitialize.EndInit()
        {
            // Resolve all properties here
            if (_unresolvedProperty != null)
            {
                try
                {
                    Property = DependencyPropertyConverter.ResolveProperty(_serviceProvider,
                        SourceName, _unresolvedProperty);
                }
                finally
                {
                    _unresolvedProperty = null;
                }
            }
            if (_unresolvedValue != null)
            {
                try
                {
                    Value = SetterTriggerConditionValueConverter.ResolveValue(_serviceProvider,
                        Property, _cultureInfoForTypeConverter, _unresolvedValue);
                }
                finally
                {
                    _unresolvedValue = null;
                }
            }
            _serviceProvider = null;
            _cultureInfoForTypeConverter = null;
        }
 
        #endregion
 
        public static void ReceiveMarkupExtension(object targetObject, XamlSetMarkupExtensionEventArgs eventArgs)
        {
            ArgumentNullException.ThrowIfNull(targetObject);
            ArgumentNullException.ThrowIfNull(eventArgs);
 
            Condition condition = targetObject as Condition;
            if (condition != null && eventArgs.Member.Name == "Binding" && eventArgs.MarkupExtension is BindingBase)
            {
                condition.Binding = eventArgs.MarkupExtension as BindingBase;
 
                eventArgs.Handled = true;
            }
        }
 
        public static void ReceiveTypeConverter(object targetObject, XamlSetTypeConverterEventArgs eventArgs)
        {
            Condition condition = targetObject as Condition;
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(targetObject));
            }
            ArgumentNullException.ThrowIfNull(eventArgs);
 
            if (eventArgs.Member.Name == "Property")
            {
                condition._unresolvedProperty = eventArgs.Value;
                condition._serviceProvider = eventArgs.ServiceProvider;
                condition._cultureInfoForTypeConverter = eventArgs.CultureInfo;
 
                eventArgs.Handled = true;
            }
            else if (eventArgs.Member.Name == "Value")
            {
                condition._unresolvedValue = eventArgs.Value;
                condition._serviceProvider = eventArgs.ServiceProvider;
                condition._cultureInfoForTypeConverter = eventArgs.CultureInfo;
 
                eventArgs.Handled = true;
            }
        }
 
 
        private bool _sealed = false;
 
        private DependencyProperty _property;
        private BindingBase _binding;
        private object _value = DependencyProperty.UnsetValue;
        private string _sourceName = null;
        private object _unresolvedProperty = null;
        private object _unresolvedValue = null;
        private ITypeDescriptorContext _serviceProvider = null;
        private CultureInfo _cultureInfoForTypeConverter = null;
    }
}