Binding.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Data / Binding.cs / 3 / Binding.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines Binding object, which describes an instance of data Binding. 
// 
// See spec at http://avalon/connecteddata/Specs/Data%20Binding.mht
// 
//---------------------------------------------------------------------------

using System;
using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.Globalization; 
using System.Diagnostics; 
using System.ComponentModel;
using System.Xml; 

using System.Windows;
using System.Windows.Controls;  // Validation
using System.Windows.Markup; 
using MS.Utility;
using MS.Internal; // Invariant.Assert 
using MS.Internal.Controls; // Validation 
using MS.Internal.Data;
using MS.Internal.KnownBoxes; 

namespace System.Windows.Data
{
 
    /// 
    /// Status of the Binding 
    ///  
    public enum BindingStatus
    { 
        ///  Binding has not yet been attached to its target 
        Unattached = 0,
        ///  Binding has not yet been activated 
        Inactive, 
        ///  Binding has been successfully activated 
        Active, 
        ///  Binding has been detached from its target  
        Detached,
        ///  Binding is waiting for an async operation to complete 
        AsyncRequestPending,
        ///  error - source path could not be resolved 
        PathError,
        ///  error - a legal value could not be obtained from the source 
        UpdateTargetError,
        ///  error - the value could not be sent to the source  
        UpdateSourceError, 
    }
 
    /// 
    ///  Describes an instance of a Binding, binding a target
    ///  (DependencyObject, DependencyProperty) to a source (object, property)
    ///  
    public class Binding : BindingBase
    { 
        //----------------------------------------------------- 
        //
        //  Enums 
        //
        //-----------------------------------------------------

        // Which source property is in use 
        enum SourceProperties : byte { None, RelativeSource, ElementName, Source, InternalSource }
 
 
        //------------------------------------------------------
        // 
        //  Dynamic properties and events
        //
        //-----------------------------------------------------
 
        /// 
        /// The SourceUpdated event is raised whenever a value is transferred from the target to the source, 
        /// but only for Bindings that have requested the event by setting BindFlags.NotifyOnSourceUpdated. 
        /// 
        public static readonly RoutedEvent SourceUpdatedEvent = 
                EventManager.RegisterRoutedEvent("SourceUpdated",
                                        RoutingStrategy.Bubble,
                                        typeof(EventHandler),
                                        typeof(Binding)); 

        ///  
        ///     Adds a handler for the SourceUpdated attached event 
        /// 
        /// UIElement or ContentElement that listens to this event 
        /// Event Handler to be added
        public static void AddSourceUpdatedHandler(DependencyObject element, EventHandler handler)
        {
            FrameworkElement.AddHandler(element, SourceUpdatedEvent, handler); 
        }
 
        ///  
        ///     Removes a handler for the SourceUpdated attached event
        ///  
        /// UIElement or ContentElement that listens to this event
        /// Event Handler to be removed
        public static void RemoveSourceUpdatedHandler(DependencyObject element, EventHandler handler)
        { 
            FrameworkElement.RemoveHandler(element, SourceUpdatedEvent, handler);
        } 
 
        /// 
        /// The TargetUpdated event is raised whenever a value is transferred from the source to the target, 
        /// but only for Bindings that have requested the event by setting BindFlags.NotifyOnTargetUpdated.
        /// 
        public static readonly RoutedEvent TargetUpdatedEvent =
                EventManager.RegisterRoutedEvent("TargetUpdated", 
                                        RoutingStrategy.Bubble,
                                        typeof(EventHandler), 
                                        typeof(Binding)); 

        ///  
        ///     Adds a handler for the TargetUpdated attached event
        /// 
        /// UIElement or ContentElement that listens to this event
        /// Event Handler to be added 
        public static void AddTargetUpdatedHandler(DependencyObject element, EventHandler handler)
        { 
            FrameworkElement.AddHandler(element, TargetUpdatedEvent, handler); 
        }
 
        /// 
        ///     Removes a handler for the TargetUpdated attached event
        /// 
        /// UIElement or ContentElement that listens to this event 
        /// Event Handler to be removed
        public static void RemoveTargetUpdatedHandler(DependencyObject element, EventHandler handler) 
        { 
            FrameworkElement.RemoveHandler(element, TargetUpdatedEvent, handler);
        } 


        // PreSharp uses message numbers that the C# compiler doesn't know about.
        // Disable the C# complaints, per the PreSharp documentation. 
        #pragma warning disable 1634, 1691
 
        // PreSharp checks that the type of the DP agrees with the type of the static 
        // accessors.  But setting the type of the DP to XmlNamespaceManager would
        // load System.Xml during the static cctor, which is considered a perf bug. 
        // So instead we set the type of the DP to 'object' and use the
        // ValidateValueCallback to ensure that only values of the right type are allowed.
        // Meanwhile, disable the PreSharp warning
        #pragma warning disable 7008 

        ///  
        /// The XmlNamespaceManager to use to perform Namespace aware XPath queries in XmlData bindings 
        /// 
        public static readonly DependencyProperty XmlNamespaceManagerProperty= 
                DependencyProperty.RegisterAttached("XmlNamespaceManager", typeof(object), typeof(Binding),
                                            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits),
                                            new ValidateValueCallback(IsValidXmlNamespaceManager));
 
        ///  Static accessor for XmlNamespaceManager property 
        ///  DependencyObject target cannot be null  
        public static XmlNamespaceManager GetXmlNamespaceManager(DependencyObject target) 
        {
            if (target == null) 
                throw new ArgumentNullException("target");

            return (XmlNamespaceManager)target.GetValue(XmlNamespaceManagerProperty);
        } 

        ///  Static modifier for XmlNamespaceManager property  
        ///  DependencyObject target cannot be null  
        public static void SetXmlNamespaceManager(DependencyObject target, XmlNamespaceManager value)
        { 
            if (target == null)
                throw new ArgumentNullException("target");

            target.SetValue(XmlNamespaceManagerProperty, value); 
        }
 
        private static bool IsValidXmlNamespaceManager(object value) 
        {
            return (value == null) || IsValidXmlNamespaceManagerHelper(value); 
        }

        // this is a separate function to avoid loading System.Xml during static ctor.
        // Property registration calls the ValidateValue callback on the default value, 
        // i.e. IsValidXmlNamespaceManager(null).
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        private static bool IsValidXmlNamespaceManagerHelper(object value) 
        {
            return (value is XmlNamespaceManager); 
        }

        #pragma warning restore 7008
        #pragma warning restore 1634, 1691 

 
        //------------------------------------------------------ 
        //
        //  Constructors 
        //
        //------------------------------------------------------

        ///  
        /// Default constructor.
        ///  
        public Binding() {} 

        ///  
        /// Convenience constructor.  Sets most fields to default values.
        /// 
        /// source path 
        public Binding(string path) 
        {
            if (path != null) 
            { 
                if (System.Windows.Threading.Dispatcher.CurrentDispatcher == null)
                    throw new InvalidOperationException();  // This is actually never called since CurrentDispatcher will throw if null. 

                _ppath = new PropertyPath(path);
                _attachedPropertiesInPath = -1;
            } 
        }
 
        //----------------------------------------------------- 
        //
        //  Public Properties 
        //
        //------------------------------------------------------

        ///  
        ///     Collection<ValidationRule> is a collection of ValidationRule
        ///     implementations on either a Binding or a MultiBinding.  Each of the rules 
        ///     is run by the binding engine when validation on update to source 
        /// 
        public Collection ValidationRules 
        {
            get
            {
                if (_validationRules == null) 
                    _validationRules = new ValidationRuleCollection();
 
                return _validationRules; 
            }
 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeValidationRules()
        { 
            return (_validationRules != null && _validationRules.Count > 0);
        }

        ///  True if an exception during source updates should be considered a validation error. 
        [DefaultValue(false)]
        public bool ValidatesOnExceptions 
        { 
            get
            { 
                return TestFlag(BindingFlags.ValidatesOnExceptions);
            }
            set
            { 
                bool currentValue = TestFlag(BindingFlags.ValidatesOnExceptions);
                if (currentValue != value) 
                { 
                    CheckSealed();
                    ChangeFlag(BindingFlags.ValidatesOnExceptions, value); 
                }
            }
        }
 
        ///  True if a data error in the source item should be considered a validation error.
        [DefaultValue(false)] 
        public bool ValidatesOnDataErrors 
        {
            get 
            {
                return TestFlag(BindingFlags.ValidatesOnDataErrors);
            }
            set 
            {
                bool currentValue = TestFlag(BindingFlags.ValidatesOnDataErrors); 
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.ValidatesOnDataErrors, value);
                }
            }
        } 

 
        ///  The source path (for CLR bindings). 
        public PropertyPath Path
        { 
            get { return _ppath; }
            set
            {
                CheckSealed(); 

                _ppath = value; 
                _attachedPropertiesInPath = -1; 
                ClearFlag(BindingFlags.PathGeneratedInternally);
            } 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializePath()
        { 
            return _ppath != null && !TestFlag(BindingFlags.PathGeneratedInternally);
        }

        ///  The XPath path (for XML bindings). 
        [DefaultValue(null)]
        public string XPath 
        { 
            get { return _xpath; }
            set 
            {
                CheckSealed();

                _xpath = value; 
            }
        } 
 
        ///  Binding mode 
        [DefaultValue(BindingMode.Default)] 
        public BindingMode Mode
        {
            get
            { 
                switch (GetFlagsWithinMask(BindingFlags.PropagationMask))
                { 
                    case BindingFlags.OneWay:           return BindingMode.OneWay; 
                    case BindingFlags.TwoWay:           return BindingMode.TwoWay;
                    case BindingFlags.OneWayToSource:   return BindingMode.OneWayToSource; 
                    case BindingFlags.OneTime:          return BindingMode.OneTime;
                    case BindingFlags.PropDefault:      return BindingMode.Default;
                }
                Invariant.Assert(false, "Unexpected BindingMode value"); 
                return 0;
            } 
            set 
            {
                CheckSealed(); 

                BindingFlags flags = FlagsFrom(value);
                if (flags == BindingFlags.IllegalInput)
                    throw new InvalidEnumArgumentException("value", (int) value, typeof(BindingMode)); 

                ChangeFlagsWithinMask(BindingFlags.PropagationMask, flags); 
            } 
        }
 
        ///  Update type 
        [DefaultValue(UpdateSourceTrigger.Default)]
        public UpdateSourceTrigger UpdateSourceTrigger
        { 
            get
            { 
                switch (GetFlagsWithinMask(BindingFlags.UpdateMask)) 
                {
                    case BindingFlags.UpdateOnPropertyChanged: return UpdateSourceTrigger.PropertyChanged; 
                    case BindingFlags.UpdateOnLostFocus:    return UpdateSourceTrigger.LostFocus;
                    case BindingFlags.UpdateExplicitly:     return UpdateSourceTrigger.Explicit;
                    case BindingFlags.UpdateDefault:        return UpdateSourceTrigger.Default;
                } 
                Invariant.Assert(false, "Unexpected UpdateSourceTrigger value");
                return 0; 
            } 
            set
            { 
                CheckSealed();

                BindingFlags flags = FlagsFrom(value);
                if (flags == BindingFlags.IllegalInput) 
                    throw new InvalidEnumArgumentException("value", (int) value, typeof(UpdateSourceTrigger));
 
                ChangeFlagsWithinMask(BindingFlags.UpdateMask, flags); 
            }
        } 

        ///  Raise SourceUpdated event whenever a value flows from target to source 
        [DefaultValue(false)]
        public bool NotifyOnSourceUpdated 
        {
            get 
            { 
                return TestFlag(BindingFlags.NotifyOnSourceUpdated);
            } 
            set
            {
                bool currentValue = TestFlag(BindingFlags.NotifyOnSourceUpdated);
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.NotifyOnSourceUpdated, value); 
                }
            } 
        }


        ///  Raise TargetUpdated event whenever a value flows from source to target  
        [DefaultValue(false)]
        public bool NotifyOnTargetUpdated 
        { 
            get
            { 
                return TestFlag(BindingFlags.NotifyOnTargetUpdated);
            }
            set
            { 
                bool currentValue = TestFlag(BindingFlags.NotifyOnTargetUpdated);
                if (currentValue != value) 
                { 
                    CheckSealed();
                    ChangeFlag(BindingFlags.NotifyOnTargetUpdated, value); 
                }
            }
        }
 
        ///  Raise ValidationError event whenever there is a ValidationError on Update
        [DefaultValue(false)] 
        public bool NotifyOnValidationError 
        {
            get 
            {
                return TestFlag(BindingFlags.NotifyOnValidationError);
            }
            set 
            {
                bool currentValue = TestFlag(BindingFlags.NotifyOnValidationError); 
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.NotifyOnValidationError, value);
                }
            }
        } 

        ///  The Converter to apply  
        [DefaultValue(null)] 
        public IValueConverter Converter
        { 
            get { return _converter; }
            set { CheckSealed();  _converter = value; }
        }
 
        /// 
        /// The parameter to pass to converter. 
        ///  
        /// 
        [DefaultValue(null)] 
        public object ConverterParameter
        {
            get { return _converterParameter; }
            set { CheckSealed();  _converterParameter = value; } 
        }
 
        ///  Culture in which to evaluate the converter  
        [DefaultValue(null)]
        [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))] 
        public CultureInfo ConverterCulture
        {
            get { return _culture; }
            set { CheckSealed();  _culture = value; } 
        }
 
        ///  object to use as the source  
        ///  To clear this property, set it to DependencyProperty.UnsetValue. 
        public object Source 
        {
            get
            {
                if (_objectSource == null) 
                    return null;
                return _objectSource.Target; 
            } 
            set
            { 
                CheckSealed();

                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.Source)
                { 
                    if (value != DependencyProperty.UnsetValue)
                    { 
                        _objectSource = new WeakReference(value); 
                        SourceReference = new ExplicitObjectRef(value);
                    } 
                    else
                    {
                        _objectSource = null;
                        SourceReference = null; 
                    }
                } 
                else 
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.Source, _sourceInUse));
            } 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeSource()
        { 
            //return _objectSource.IsAlive && _objectSource.Target != DependencyProperty.UnsetValue;

            // M8.2: always false
            return false; 
        }
 
        ///  
        /// Description of the object to use as the source, relative to the target element.
        ///  
        [DefaultValue(null)]
        public RelativeSource RelativeSource
        {
            get { return _relativeSource; } 
            set
            { 
                CheckSealed(); 

                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.RelativeSource) 
                {
                    _relativeSource = value;
                    SourceReference = (value != null) ? new RelativeObjectRef(value) : null;
                } 
                else
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.RelativeSource, _sourceInUse)); 
            } 
        }
 
        ///  Name of the element to use as the source 
        [DefaultValue(null)]
        public string ElementName
        { 
            get { return _elementSource; }
            set 
            { 
                CheckSealed();
 
                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.ElementName)
                {
                    _elementSource = value;
                    SourceReference = (value != null) ? new ElementObjectRef(value) : null; 
                }
                else 
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.ElementName, _sourceInUse)); 
            }
        } 

        ///  True if Binding should get/set values asynchronously 
        [DefaultValue(false)]
        public bool IsAsync 
        {
            get { return _isAsync; } 
            set { CheckSealed();  _isAsync = value; } 
        }
 
        ///  Opaque data passed to the asynchronous data dispatcher 
        [DefaultValue(null)]
        public object AsyncState
        { 
            get { return _asyncState; }
            set { CheckSealed();  _asyncState = value; } 
        } 

        ///  True if Binding should interpret its path relative to 
        /// the data item itself.
        /// 
        /// 
        /// The normal behavior (when this property is false) 
        /// includes special treatment for a data item that implements IDataSource.
        /// In this case, the path is treated relative to the object obtained 
        /// from the IDataSource.Data property.  In addition, the binding listens 
        /// for the IDataSource.DataChanged event and reacts accordingly.
        /// Setting this property to true overrides this behavior and gives 
        /// the binding access to properties on the data source object itself.
        /// 
        [DefaultValue(false)]
        public bool BindsDirectlyToSource 
        {
            get { return _bindsDirectlyToSource; } 
            set { CheckSealed();  _bindsDirectlyToSource = value; } 
        }
 
        /// 
        /// called whenever any exception is encountered when trying to update
        /// the value to the source. The application author can provide its own
        /// handler for handling exceptions here. If the delegate returns 
        ///     null - don't throw an error or provide a ValidationError.
        ///     Exception - returns the exception itself, we will fire the exception using Async exception model. 
        ///     ValidationError - it will set itself as the BindingInError and add it to the element's Validation errors. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
        {
            get
            { 
                return _exceptionFilterCallback;
            } 
 
            set
            { 
                _exceptionFilterCallback = value;
            }
        }
 
        //-----------------------------------------------------
        // 
        //  Public Fields 
        //
        //----------------------------------------------------- 

        /// 
        ///     A source property or a converter can return Binding.DoNothing
        ///     to instruct the binding engine to do nothing (i.e. do not transfer 
        ///     a value to the target, do not move to the next Binding in a
        ///     PriorityBinding, do not use the fallback or default value). 
        ///  
        public static readonly object DoNothing = new NamedObject("Binding.DoNothing");
 
        /// 
        ///     This string is used as the PropertyName of the
        ///     PropertyChangedEventArgs to indicate that an indexer property
        ///     has been changed. 
        /// 
        public const string IndexerName = "Item[]"; 
 
        //-----------------------------------------------------
        // 
        //  Protected Methods
        //
        //------------------------------------------------------
 
        /// 
        /// Create an appropriate expression for this Binding, to be attached 
        /// to the given DependencyProperty on the given DependencyObject. 
        /// 
        internal override BindingExpressionBase CreateBindingExpressionOverride(DependencyObject target, DependencyProperty dp, BindingExpressionBase owner) 
        {
            return BindingExpression.CreateBindingExpression(target, dp, this, owner);
        }
 
        internal override ValidationRule LookupValidationRule(Type type)
        { 
            return LookupValidationRule(type, ValidationRulesInternal); 
        }
 
        //-----------------------------------------------------
        //
        //  Internal Methods
        // 
        //------------------------------------------------------
 
        internal object DoFilterException(object bindExpr, Exception exception) 
        {
            if (_exceptionFilterCallback != null) 
                return _exceptionFilterCallback(bindExpr, exception);

            return exception;
        } 

        // called by BindingExpression when the Binding doesn't specify a path. 
        // (Can't use Path setter, since that replaces the BindingExpression.) 
        internal void UsePath(PropertyPath path)
        { 
            _ppath = path;
            SetFlag(BindingFlags.PathGeneratedInternally);
        }
 

        //------------------------------------------------------ 
        // 
        //  Internal Properties
        // 
        //-----------------------------------------------------

        internal override CultureInfo ConverterCultureInternal
        { 
            get { return ConverterCulture; }
        } 
 
        internal ObjectRef SourceReference
        { 
            get { return (_source == UnsetSource) ? null : _source; }
            set { CheckSealed();  _source = value;  DetermineSource(); }
        }
 
        internal object WorkerData
        { 
            get { return _workerData; } 
            set { _workerData = value; }
        } 

        internal bool TreeContextIsRequired
        {
            get 
            {
                bool treeContextIsRequired; 
 
                // attached properties in the property path (like "(DockPanel.Dock)")
                // need inherited value of XmlAttributeProperties properties for namespaces, 
                // unless the properties are pre-resolved by the parser
                if (_attachedPropertiesInPath < 0)
                {
                    if (_ppath != null) 
                    {
                        _attachedPropertiesInPath = _ppath.ComputeUnresolvedAttachedPropertiesInPath(); 
                    } 
                    else
                    { 
                        _attachedPropertiesInPath = 0;
                    }
                }
                treeContextIsRequired = (_attachedPropertiesInPath > 0); 

                // namespace prefixes in the XPath need an XmlNamespaceManager 
                if (!treeContextIsRequired && !String.IsNullOrEmpty(XPath) && XPath.IndexOf(':') >= 0) 
                {
                    treeContextIsRequired = true; 
                }

                return treeContextIsRequired;
            } 
        }
 
        // same as the public ValidationRules property, but 
        // doesn't try to create an instance if there isn't one there
        internal override Collection ValidationRulesInternal 
        {
            get
            {
                return _validationRules; 
            }
        } 
 
        // when the source property has its default value, this flag controls
        // whether the binding transfers the value anyway, or simply "hides" 
        // so that the property engine obtains the target value some other way.
        internal bool TransfersDefaultValue
        {
            get { return !_doesNotTransferDefaultValue; } 
            set { CheckSealed();  _doesNotTransferDefaultValue = !value; }
        } 
 

        //------------------------------------------------------ 
        //
        //  Private Methods
        //
        //----------------------------------------------------- 

        // determine the source property currently in use 
        void DetermineSource() 
        {
            _sourceInUse = 
                (_source == UnsetSource)                ? SourceProperties.None :
                (_relativeSource != null)               ? SourceProperties.RelativeSource :
                (_elementSource != null)                ? SourceProperties.ElementName :
                (_objectSource != null)                 ? SourceProperties.Source : 
                                                          SourceProperties.InternalSource;
        } 
 
        //-----------------------------------------------------
        // 
        //  Private Fields
        //
        //-----------------------------------------------------
 
        object              _workerData;
        SourceProperties    _sourceInUse; 
 
        PropertyPath        _ppath;
        string              _xpath; 
        ObjectRef           _source = UnsetSource;
        CultureInfo         _culture;

        bool                _isAsync; 
        object              _asyncState;
        bool                _bindsDirectlyToSource; 
        bool                _doesNotTransferDefaultValue;   // initially = false 

        WeakReference       _objectSource; 
        RelativeSource      _relativeSource;
        string              _elementSource;
        IValueConverter     _converter;
        object              _converterParameter; 

        int                 _attachedPropertiesInPath; 
        ValidationRuleCollection _validationRules; 
        UpdateSourceExceptionFilterCallback _exceptionFilterCallback;
 
        static readonly ObjectRef UnsetSource = new ExplicitObjectRef(null);
    }
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines Binding object, which describes an instance of data Binding. 
// 
// See spec at http://avalon/connecteddata/Specs/Data%20Binding.mht
// 
//---------------------------------------------------------------------------

using System;
using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.Globalization; 
using System.Diagnostics; 
using System.ComponentModel;
using System.Xml; 

using System.Windows;
using System.Windows.Controls;  // Validation
using System.Windows.Markup; 
using MS.Utility;
using MS.Internal; // Invariant.Assert 
using MS.Internal.Controls; // Validation 
using MS.Internal.Data;
using MS.Internal.KnownBoxes; 

namespace System.Windows.Data
{
 
    /// 
    /// Status of the Binding 
    ///  
    public enum BindingStatus
    { 
        ///  Binding has not yet been attached to its target 
        Unattached = 0,
        ///  Binding has not yet been activated 
        Inactive, 
        ///  Binding has been successfully activated 
        Active, 
        ///  Binding has been detached from its target  
        Detached,
        ///  Binding is waiting for an async operation to complete 
        AsyncRequestPending,
        ///  error - source path could not be resolved 
        PathError,
        ///  error - a legal value could not be obtained from the source 
        UpdateTargetError,
        ///  error - the value could not be sent to the source  
        UpdateSourceError, 
    }
 
    /// 
    ///  Describes an instance of a Binding, binding a target
    ///  (DependencyObject, DependencyProperty) to a source (object, property)
    ///  
    public class Binding : BindingBase
    { 
        //----------------------------------------------------- 
        //
        //  Enums 
        //
        //-----------------------------------------------------

        // Which source property is in use 
        enum SourceProperties : byte { None, RelativeSource, ElementName, Source, InternalSource }
 
 
        //------------------------------------------------------
        // 
        //  Dynamic properties and events
        //
        //-----------------------------------------------------
 
        /// 
        /// The SourceUpdated event is raised whenever a value is transferred from the target to the source, 
        /// but only for Bindings that have requested the event by setting BindFlags.NotifyOnSourceUpdated. 
        /// 
        public static readonly RoutedEvent SourceUpdatedEvent = 
                EventManager.RegisterRoutedEvent("SourceUpdated",
                                        RoutingStrategy.Bubble,
                                        typeof(EventHandler),
                                        typeof(Binding)); 

        ///  
        ///     Adds a handler for the SourceUpdated attached event 
        /// 
        /// UIElement or ContentElement that listens to this event 
        /// Event Handler to be added
        public static void AddSourceUpdatedHandler(DependencyObject element, EventHandler handler)
        {
            FrameworkElement.AddHandler(element, SourceUpdatedEvent, handler); 
        }
 
        ///  
        ///     Removes a handler for the SourceUpdated attached event
        ///  
        /// UIElement or ContentElement that listens to this event
        /// Event Handler to be removed
        public static void RemoveSourceUpdatedHandler(DependencyObject element, EventHandler handler)
        { 
            FrameworkElement.RemoveHandler(element, SourceUpdatedEvent, handler);
        } 
 
        /// 
        /// The TargetUpdated event is raised whenever a value is transferred from the source to the target, 
        /// but only for Bindings that have requested the event by setting BindFlags.NotifyOnTargetUpdated.
        /// 
        public static readonly RoutedEvent TargetUpdatedEvent =
                EventManager.RegisterRoutedEvent("TargetUpdated", 
                                        RoutingStrategy.Bubble,
                                        typeof(EventHandler), 
                                        typeof(Binding)); 

        ///  
        ///     Adds a handler for the TargetUpdated attached event
        /// 
        /// UIElement or ContentElement that listens to this event
        /// Event Handler to be added 
        public static void AddTargetUpdatedHandler(DependencyObject element, EventHandler handler)
        { 
            FrameworkElement.AddHandler(element, TargetUpdatedEvent, handler); 
        }
 
        /// 
        ///     Removes a handler for the TargetUpdated attached event
        /// 
        /// UIElement or ContentElement that listens to this event 
        /// Event Handler to be removed
        public static void RemoveTargetUpdatedHandler(DependencyObject element, EventHandler handler) 
        { 
            FrameworkElement.RemoveHandler(element, TargetUpdatedEvent, handler);
        } 


        // PreSharp uses message numbers that the C# compiler doesn't know about.
        // Disable the C# complaints, per the PreSharp documentation. 
        #pragma warning disable 1634, 1691
 
        // PreSharp checks that the type of the DP agrees with the type of the static 
        // accessors.  But setting the type of the DP to XmlNamespaceManager would
        // load System.Xml during the static cctor, which is considered a perf bug. 
        // So instead we set the type of the DP to 'object' and use the
        // ValidateValueCallback to ensure that only values of the right type are allowed.
        // Meanwhile, disable the PreSharp warning
        #pragma warning disable 7008 

        ///  
        /// The XmlNamespaceManager to use to perform Namespace aware XPath queries in XmlData bindings 
        /// 
        public static readonly DependencyProperty XmlNamespaceManagerProperty= 
                DependencyProperty.RegisterAttached("XmlNamespaceManager", typeof(object), typeof(Binding),
                                            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits),
                                            new ValidateValueCallback(IsValidXmlNamespaceManager));
 
        ///  Static accessor for XmlNamespaceManager property 
        ///  DependencyObject target cannot be null  
        public static XmlNamespaceManager GetXmlNamespaceManager(DependencyObject target) 
        {
            if (target == null) 
                throw new ArgumentNullException("target");

            return (XmlNamespaceManager)target.GetValue(XmlNamespaceManagerProperty);
        } 

        ///  Static modifier for XmlNamespaceManager property  
        ///  DependencyObject target cannot be null  
        public static void SetXmlNamespaceManager(DependencyObject target, XmlNamespaceManager value)
        { 
            if (target == null)
                throw new ArgumentNullException("target");

            target.SetValue(XmlNamespaceManagerProperty, value); 
        }
 
        private static bool IsValidXmlNamespaceManager(object value) 
        {
            return (value == null) || IsValidXmlNamespaceManagerHelper(value); 
        }

        // this is a separate function to avoid loading System.Xml during static ctor.
        // Property registration calls the ValidateValue callback on the default value, 
        // i.e. IsValidXmlNamespaceManager(null).
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        private static bool IsValidXmlNamespaceManagerHelper(object value) 
        {
            return (value is XmlNamespaceManager); 
        }

        #pragma warning restore 7008
        #pragma warning restore 1634, 1691 

 
        //------------------------------------------------------ 
        //
        //  Constructors 
        //
        //------------------------------------------------------

        ///  
        /// Default constructor.
        ///  
        public Binding() {} 

        ///  
        /// Convenience constructor.  Sets most fields to default values.
        /// 
        /// source path 
        public Binding(string path) 
        {
            if (path != null) 
            { 
                if (System.Windows.Threading.Dispatcher.CurrentDispatcher == null)
                    throw new InvalidOperationException();  // This is actually never called since CurrentDispatcher will throw if null. 

                _ppath = new PropertyPath(path);
                _attachedPropertiesInPath = -1;
            } 
        }
 
        //----------------------------------------------------- 
        //
        //  Public Properties 
        //
        //------------------------------------------------------

        ///  
        ///     Collection<ValidationRule> is a collection of ValidationRule
        ///     implementations on either a Binding or a MultiBinding.  Each of the rules 
        ///     is run by the binding engine when validation on update to source 
        /// 
        public Collection ValidationRules 
        {
            get
            {
                if (_validationRules == null) 
                    _validationRules = new ValidationRuleCollection();
 
                return _validationRules; 
            }
 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeValidationRules()
        { 
            return (_validationRules != null && _validationRules.Count > 0);
        }

        ///  True if an exception during source updates should be considered a validation error. 
        [DefaultValue(false)]
        public bool ValidatesOnExceptions 
        { 
            get
            { 
                return TestFlag(BindingFlags.ValidatesOnExceptions);
            }
            set
            { 
                bool currentValue = TestFlag(BindingFlags.ValidatesOnExceptions);
                if (currentValue != value) 
                { 
                    CheckSealed();
                    ChangeFlag(BindingFlags.ValidatesOnExceptions, value); 
                }
            }
        }
 
        ///  True if a data error in the source item should be considered a validation error.
        [DefaultValue(false)] 
        public bool ValidatesOnDataErrors 
        {
            get 
            {
                return TestFlag(BindingFlags.ValidatesOnDataErrors);
            }
            set 
            {
                bool currentValue = TestFlag(BindingFlags.ValidatesOnDataErrors); 
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.ValidatesOnDataErrors, value);
                }
            }
        } 

 
        ///  The source path (for CLR bindings). 
        public PropertyPath Path
        { 
            get { return _ppath; }
            set
            {
                CheckSealed(); 

                _ppath = value; 
                _attachedPropertiesInPath = -1; 
                ClearFlag(BindingFlags.PathGeneratedInternally);
            } 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializePath()
        { 
            return _ppath != null && !TestFlag(BindingFlags.PathGeneratedInternally);
        }

        ///  The XPath path (for XML bindings). 
        [DefaultValue(null)]
        public string XPath 
        { 
            get { return _xpath; }
            set 
            {
                CheckSealed();

                _xpath = value; 
            }
        } 
 
        ///  Binding mode 
        [DefaultValue(BindingMode.Default)] 
        public BindingMode Mode
        {
            get
            { 
                switch (GetFlagsWithinMask(BindingFlags.PropagationMask))
                { 
                    case BindingFlags.OneWay:           return BindingMode.OneWay; 
                    case BindingFlags.TwoWay:           return BindingMode.TwoWay;
                    case BindingFlags.OneWayToSource:   return BindingMode.OneWayToSource; 
                    case BindingFlags.OneTime:          return BindingMode.OneTime;
                    case BindingFlags.PropDefault:      return BindingMode.Default;
                }
                Invariant.Assert(false, "Unexpected BindingMode value"); 
                return 0;
            } 
            set 
            {
                CheckSealed(); 

                BindingFlags flags = FlagsFrom(value);
                if (flags == BindingFlags.IllegalInput)
                    throw new InvalidEnumArgumentException("value", (int) value, typeof(BindingMode)); 

                ChangeFlagsWithinMask(BindingFlags.PropagationMask, flags); 
            } 
        }
 
        ///  Update type 
        [DefaultValue(UpdateSourceTrigger.Default)]
        public UpdateSourceTrigger UpdateSourceTrigger
        { 
            get
            { 
                switch (GetFlagsWithinMask(BindingFlags.UpdateMask)) 
                {
                    case BindingFlags.UpdateOnPropertyChanged: return UpdateSourceTrigger.PropertyChanged; 
                    case BindingFlags.UpdateOnLostFocus:    return UpdateSourceTrigger.LostFocus;
                    case BindingFlags.UpdateExplicitly:     return UpdateSourceTrigger.Explicit;
                    case BindingFlags.UpdateDefault:        return UpdateSourceTrigger.Default;
                } 
                Invariant.Assert(false, "Unexpected UpdateSourceTrigger value");
                return 0; 
            } 
            set
            { 
                CheckSealed();

                BindingFlags flags = FlagsFrom(value);
                if (flags == BindingFlags.IllegalInput) 
                    throw new InvalidEnumArgumentException("value", (int) value, typeof(UpdateSourceTrigger));
 
                ChangeFlagsWithinMask(BindingFlags.UpdateMask, flags); 
            }
        } 

        ///  Raise SourceUpdated event whenever a value flows from target to source 
        [DefaultValue(false)]
        public bool NotifyOnSourceUpdated 
        {
            get 
            { 
                return TestFlag(BindingFlags.NotifyOnSourceUpdated);
            } 
            set
            {
                bool currentValue = TestFlag(BindingFlags.NotifyOnSourceUpdated);
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.NotifyOnSourceUpdated, value); 
                }
            } 
        }


        ///  Raise TargetUpdated event whenever a value flows from source to target  
        [DefaultValue(false)]
        public bool NotifyOnTargetUpdated 
        { 
            get
            { 
                return TestFlag(BindingFlags.NotifyOnTargetUpdated);
            }
            set
            { 
                bool currentValue = TestFlag(BindingFlags.NotifyOnTargetUpdated);
                if (currentValue != value) 
                { 
                    CheckSealed();
                    ChangeFlag(BindingFlags.NotifyOnTargetUpdated, value); 
                }
            }
        }
 
        ///  Raise ValidationError event whenever there is a ValidationError on Update
        [DefaultValue(false)] 
        public bool NotifyOnValidationError 
        {
            get 
            {
                return TestFlag(BindingFlags.NotifyOnValidationError);
            }
            set 
            {
                bool currentValue = TestFlag(BindingFlags.NotifyOnValidationError); 
                if (currentValue != value) 
                {
                    CheckSealed(); 
                    ChangeFlag(BindingFlags.NotifyOnValidationError, value);
                }
            }
        } 

        ///  The Converter to apply  
        [DefaultValue(null)] 
        public IValueConverter Converter
        { 
            get { return _converter; }
            set { CheckSealed();  _converter = value; }
        }
 
        /// 
        /// The parameter to pass to converter. 
        ///  
        /// 
        [DefaultValue(null)] 
        public object ConverterParameter
        {
            get { return _converterParameter; }
            set { CheckSealed();  _converterParameter = value; } 
        }
 
        ///  Culture in which to evaluate the converter  
        [DefaultValue(null)]
        [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))] 
        public CultureInfo ConverterCulture
        {
            get { return _culture; }
            set { CheckSealed();  _culture = value; } 
        }
 
        ///  object to use as the source  
        ///  To clear this property, set it to DependencyProperty.UnsetValue. 
        public object Source 
        {
            get
            {
                if (_objectSource == null) 
                    return null;
                return _objectSource.Target; 
            } 
            set
            { 
                CheckSealed();

                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.Source)
                { 
                    if (value != DependencyProperty.UnsetValue)
                    { 
                        _objectSource = new WeakReference(value); 
                        SourceReference = new ExplicitObjectRef(value);
                    } 
                    else
                    {
                        _objectSource = null;
                        SourceReference = null; 
                    }
                } 
                else 
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.Source, _sourceInUse));
            } 
        }

        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeSource()
        { 
            //return _objectSource.IsAlive && _objectSource.Target != DependencyProperty.UnsetValue;

            // M8.2: always false
            return false; 
        }
 
        ///  
        /// Description of the object to use as the source, relative to the target element.
        ///  
        [DefaultValue(null)]
        public RelativeSource RelativeSource
        {
            get { return _relativeSource; } 
            set
            { 
                CheckSealed(); 

                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.RelativeSource) 
                {
                    _relativeSource = value;
                    SourceReference = (value != null) ? new RelativeObjectRef(value) : null;
                } 
                else
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.RelativeSource, _sourceInUse)); 
            } 
        }
 
        ///  Name of the element to use as the source 
        [DefaultValue(null)]
        public string ElementName
        { 
            get { return _elementSource; }
            set 
            { 
                CheckSealed();
 
                if (_sourceInUse == SourceProperties.None || _sourceInUse == SourceProperties.ElementName)
                {
                    _elementSource = value;
                    SourceReference = (value != null) ? new ElementObjectRef(value) : null; 
                }
                else 
                    throw new InvalidOperationException(SR.Get(SRID.BindingConflict, SourceProperties.ElementName, _sourceInUse)); 
            }
        } 

        ///  True if Binding should get/set values asynchronously 
        [DefaultValue(false)]
        public bool IsAsync 
        {
            get { return _isAsync; } 
            set { CheckSealed();  _isAsync = value; } 
        }
 
        ///  Opaque data passed to the asynchronous data dispatcher 
        [DefaultValue(null)]
        public object AsyncState
        { 
            get { return _asyncState; }
            set { CheckSealed();  _asyncState = value; } 
        } 

        ///  True if Binding should interpret its path relative to 
        /// the data item itself.
        /// 
        /// 
        /// The normal behavior (when this property is false) 
        /// includes special treatment for a data item that implements IDataSource.
        /// In this case, the path is treated relative to the object obtained 
        /// from the IDataSource.Data property.  In addition, the binding listens 
        /// for the IDataSource.DataChanged event and reacts accordingly.
        /// Setting this property to true overrides this behavior and gives 
        /// the binding access to properties on the data source object itself.
        /// 
        [DefaultValue(false)]
        public bool BindsDirectlyToSource 
        {
            get { return _bindsDirectlyToSource; } 
            set { CheckSealed();  _bindsDirectlyToSource = value; } 
        }
 
        /// 
        /// called whenever any exception is encountered when trying to update
        /// the value to the source. The application author can provide its own
        /// handler for handling exceptions here. If the delegate returns 
        ///     null - don't throw an error or provide a ValidationError.
        ///     Exception - returns the exception itself, we will fire the exception using Async exception model. 
        ///     ValidationError - it will set itself as the BindingInError and add it to the element's Validation errors. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
        {
            get
            { 
                return _exceptionFilterCallback;
            } 
 
            set
            { 
                _exceptionFilterCallback = value;
            }
        }
 
        //-----------------------------------------------------
        // 
        //  Public Fields 
        //
        //----------------------------------------------------- 

        /// 
        ///     A source property or a converter can return Binding.DoNothing
        ///     to instruct the binding engine to do nothing (i.e. do not transfer 
        ///     a value to the target, do not move to the next Binding in a
        ///     PriorityBinding, do not use the fallback or default value). 
        ///  
        public static readonly object DoNothing = new NamedObject("Binding.DoNothing");
 
        /// 
        ///     This string is used as the PropertyName of the
        ///     PropertyChangedEventArgs to indicate that an indexer property
        ///     has been changed. 
        /// 
        public const string IndexerName = "Item[]"; 
 
        //-----------------------------------------------------
        // 
        //  Protected Methods
        //
        //------------------------------------------------------
 
        /// 
        /// Create an appropriate expression for this Binding, to be attached 
        /// to the given DependencyProperty on the given DependencyObject. 
        /// 
        internal override BindingExpressionBase CreateBindingExpressionOverride(DependencyObject target, DependencyProperty dp, BindingExpressionBase owner) 
        {
            return BindingExpression.CreateBindingExpression(target, dp, this, owner);
        }
 
        internal override ValidationRule LookupValidationRule(Type type)
        { 
            return LookupValidationRule(type, ValidationRulesInternal); 
        }
 
        //-----------------------------------------------------
        //
        //  Internal Methods
        // 
        //------------------------------------------------------
 
        internal object DoFilterException(object bindExpr, Exception exception) 
        {
            if (_exceptionFilterCallback != null) 
                return _exceptionFilterCallback(bindExpr, exception);

            return exception;
        } 

        // called by BindingExpression when the Binding doesn't specify a path. 
        // (Can't use Path setter, since that replaces the BindingExpression.) 
        internal void UsePath(PropertyPath path)
        { 
            _ppath = path;
            SetFlag(BindingFlags.PathGeneratedInternally);
        }
 

        //------------------------------------------------------ 
        // 
        //  Internal Properties
        // 
        //-----------------------------------------------------

        internal override CultureInfo ConverterCultureInternal
        { 
            get { return ConverterCulture; }
        } 
 
        internal ObjectRef SourceReference
        { 
            get { return (_source == UnsetSource) ? null : _source; }
            set { CheckSealed();  _source = value;  DetermineSource(); }
        }
 
        internal object WorkerData
        { 
            get { return _workerData; } 
            set { _workerData = value; }
        } 

        internal bool TreeContextIsRequired
        {
            get 
            {
                bool treeContextIsRequired; 
 
                // attached properties in the property path (like "(DockPanel.Dock)")
                // need inherited value of XmlAttributeProperties properties for namespaces, 
                // unless the properties are pre-resolved by the parser
                if (_attachedPropertiesInPath < 0)
                {
                    if (_ppath != null) 
                    {
                        _attachedPropertiesInPath = _ppath.ComputeUnresolvedAttachedPropertiesInPath(); 
                    } 
                    else
                    { 
                        _attachedPropertiesInPath = 0;
                    }
                }
                treeContextIsRequired = (_attachedPropertiesInPath > 0); 

                // namespace prefixes in the XPath need an XmlNamespaceManager 
                if (!treeContextIsRequired && !String.IsNullOrEmpty(XPath) && XPath.IndexOf(':') >= 0) 
                {
                    treeContextIsRequired = true; 
                }

                return treeContextIsRequired;
            } 
        }
 
        // same as the public ValidationRules property, but 
        // doesn't try to create an instance if there isn't one there
        internal override Collection ValidationRulesInternal 
        {
            get
            {
                return _validationRules; 
            }
        } 
 
        // when the source property has its default value, this flag controls
        // whether the binding transfers the value anyway, or simply "hides" 
        // so that the property engine obtains the target value some other way.
        internal bool TransfersDefaultValue
        {
            get { return !_doesNotTransferDefaultValue; } 
            set { CheckSealed();  _doesNotTransferDefaultValue = !value; }
        } 
 

        //------------------------------------------------------ 
        //
        //  Private Methods
        //
        //----------------------------------------------------- 

        // determine the source property currently in use 
        void DetermineSource() 
        {
            _sourceInUse = 
                (_source == UnsetSource)                ? SourceProperties.None :
                (_relativeSource != null)               ? SourceProperties.RelativeSource :
                (_elementSource != null)                ? SourceProperties.ElementName :
                (_objectSource != null)                 ? SourceProperties.Source : 
                                                          SourceProperties.InternalSource;
        } 
 
        //-----------------------------------------------------
        // 
        //  Private Fields
        //
        //-----------------------------------------------------
 
        object              _workerData;
        SourceProperties    _sourceInUse; 
 
        PropertyPath        _ppath;
        string              _xpath; 
        ObjectRef           _source = UnsetSource;
        CultureInfo         _culture;

        bool                _isAsync; 
        object              _asyncState;
        bool                _bindsDirectlyToSource; 
        bool                _doesNotTransferDefaultValue;   // initially = false 

        WeakReference       _objectSource; 
        RelativeSource      _relativeSource;
        string              _elementSource;
        IValueConverter     _converter;
        object              _converterParameter; 

        int                 _attachedPropertiesInPath; 
        ValidationRuleCollection _validationRules; 
        UpdateSourceExceptionFilterCallback _exceptionFilterCallback;
 
        static readonly ObjectRef UnsetSource = new ExplicitObjectRef(null);
    }
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK