BindingExpression.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Data / BindingExpression.cs / 6 / BindingExpression.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines BindingExpression object, the run-time instance of data binding. 
// 
// See spec at [....]/connecteddata/Specs/Data%20Binding.mht
// 
//---------------------------------------------------------------------------

using System;
using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Diagnostics; 
using System.ComponentModel;
using System.Globalization; 
using System.Windows.Threading;
using System.Threading;
using System.Xml;
using System.Windows; 
using System.Windows.Input;
using System.Windows.Controls; 
using System.Windows.Markup; 
using MS.Utility;
using MS.Internal; 
using MS.Internal.Controls; // Validation
using MS.Internal.Data;
using MS.Internal.KnownBoxes;
using MS.Internal.Utility;  // TraceLog 

namespace System.Windows.Data 
{ 

 
    /// 
    /// 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 - dont 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 elements Validation errors. 
    /// 
    public delegate object UpdateSourceExceptionFilterCallback(object bindExpression, Exception exception); 

    /// 
    ///  Describes a single run-time instance of data binding, binding a target
    ///  (element, DependencyProperty) to a source (object, property, XML node) 
    /// 
    public sealed class BindingExpression : BindingExpressionBase, IDataBindEngineClient, IWeakEventListener 
    { 
        //-----------------------------------------------------
        // 
        //  Enums
        //
        //-----------------------------------------------------
 
        internal enum SourceType { Unknown, CLR, XML }
        private enum AttachAttempt { First, Again, Last } 
 
        //------------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        private BindingExpression(Binding binding, BindingExpressionBase owner)
            : base(binding, owner) 
        { 
            UseDefaultValueConverter = (ParentBinding.Converter == null);
 
            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ShowPath))
            {
                PropertyPath pp = binding.Path;
                string path = (pp != null) ? pp.Path : String.Empty; 

                if (String.IsNullOrEmpty(binding.XPath)) 
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.BindingPath( 
                                            TraceData.Identify(path)));
                }
                else
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.BindingXPathAndPath( 
                                            TraceData.Identify(binding.XPath), 
                                            TraceData.Identify(path)));
                } 
            }
        }

        //------------------------------------------------------ 
        //
        //  Interfaces 
        // 
        //------------------------------------------------------
 
        void IDataBindEngineClient.TransferValue()
        {
            TransferValue();
        } 

        void IDataBindEngineClient.UpdateValue() 
        { 
            UpdateValue();
        } 

        bool IDataBindEngineClient.AttachToContext(bool lastChance)
        {
            AttachToContext(lastChance ? AttachAttempt.Last : AttachAttempt.Again); 
            return (Status != BindingStatus.Unattached);
        } 
 
        void IDataBindEngineClient.OnTargetUpdated()
        { 
            OnTargetUpdated();
        }

        DependencyObject IDataBindEngineClient.TargetElement 
        {
            get { return TargetElement; } 
        } 

        //----------------------------------------------------- 
        //
        //  Public Properties
        //
        //------------------------------------------------------ 

        ///  Binding from which this expression was created  
        public Binding ParentBinding { get { return (Binding)ParentBindingBase; } } 

        /// The data item actually used by this BindingExpression 
        public object DataItem { get { return GetReference(_dataItem); } }

        /// The data source actually used by this BindingExpression
        internal object DataSource 
        {
            get 
            { 
                DependencyObject target = TargetElement;
                if (target == null) 
                    return null;

                // if we're using DataContext, find the source for the DataContext
                if (_ctxElement != null) 
                    return GetDataSourceForDataContext(ContextElement);
 
                // otherwise use the explicit source 
                ObjectRef or = ParentBinding.SourceReference;
                return or.GetObject(target, false); 
            }
        }

        //----------------------------------------------------- 
        //
        //  Public Methods 
        // 
        //-----------------------------------------------------
 
        ///  Send the current value back to the source 
        ///  Does nothing when binding's Mode is not TwoWay or OneWayToSource 
        public override void UpdateSource()
        { 
            if (Status == BindingStatus.Detached)
                throw new InvalidOperationException(SR.Get(SRID.BindingExpressionIsDetached)); 
 
            NeedsUpdate = true;     // force update
            Update(true);           // update synchronously 
        }

        ///  Force a data transfer from source to target 
        public override void UpdateTarget() 
        {
            if (Status == BindingStatus.Detached) 
                throw new InvalidOperationException(SR.Get(SRID.BindingExpressionIsDetached)); 

            if (Worker != null) 
            {
                Worker.RefreshValue();  // calls TransferValue
            }
        } 

#region Expression overrides 
 
        /// 
        ///     Called to evaluate the Expression value 
        /// 
        /// DependencyObject being queried
        /// Property being queried
        /// Computed value. Default (of the target) if unavailable. 
        internal override object GetValue(DependencyObject d, DependencyProperty dp)
        { 
            return Value; 
        }
 
        /// 
        ///     Allows Expression to store set values
        /// 
        /// DependencyObject being set 
        /// Property being set
        /// Value being set 
        /// true if Expression handled storing of the value 
        internal override bool SetValue(DependencyObject d, DependencyProperty dp, object value)
        { 
            if (IsReflective)
            {
                Value = value;
                return true; 
            }
            else 
            { 
                // if the binding doesn't push values back to the source, allow
                // SetValue to overwrite the binding with a local value 
                return false;
            }
        }
 
        /// 
        ///     Notification that a Dependent that this Expression established has 
        ///     been invalidated as a result of a Source invalidation 
        /// 
        /// DependencyObject that was invalidated 
        /// Changed event args for the property that was invalidated
        internal override void OnPropertyInvalidation(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            if (d == null) 
                throw new ArgumentNullException("d");
 
            DependencyProperty dp = args.Property; 
            if (dp == null)
                throw new ArgumentNullException("dp"); 

            // ignore irrelevant notifications.  This test must happen before any marshalling.
            bool relevant = !IgnoreSourcePropertyChange;
 
            if (dp == FrameworkElement.DataContextProperty && d == ContextElement)
            { 
                relevant = true;    // changes from context element are always relevant 
            }
            else if (dp == CollectionViewSource.ViewProperty && d == CollectionViewSource) 
            {
                relevant = true;    // changes from the CollectionViewSource are always relevant
            }
            else if (relevant) 
            {
                relevant = (Worker != null) && (Worker.UsesDependencyProperty(d, dp)); 
            } 

            if (!relevant) 
                return;

            // if the notification arrived on the right Dispatcher, handle it now.
            if (Dispatcher.Thread == Thread.CurrentThread) 
            {
                HandlePropertyInvalidation(d, args); 
            } 
            else    // Otherwise, marshal it to the right Dispatcher.
            { 
                IsTransferPending = true;
                Dispatcher.BeginInvoke(
                    DispatcherPriority.DataBind,
                    new DispatcherOperationCallback(HandlePropertyInvalidationOperation), 
                    new object[]{d, args});
            } 
        } 

#endregion  Expression overrides 

        //-----------------------------------------------------
        //
        //  Protected Methods 
        //
        //------------------------------------------------------ 
 
        /// 
        /// Invalidate the given child expression. 
        /// 
        internal override void InvalidateChild(BindingExpressionBase bindingExpression)
        {
            // BindingExpression does not support child bindings 
        }
 
        ///  
        /// Change the dependency sources for the given child expression.
        ///  
        internal override void ChangeSourcesForChild(BindingExpressionBase bindingExpression, WeakDependencySource[] newSources)
        {
            // BindingExpression does not support child bindings
        } 

        ///  
        /// Replace the given child expression with a new one. 
        /// 
        internal override void ReplaceChild(BindingExpressionBase bindingExpression) 
        {
            // BindingExpression does not support child bindings
        }
 
        //-----------------------------------------------------
        // 
        //  Internal Properties 
        //
        //------------------------------------------------------ 

        // The ContextElement is the DependencyObject (if any) whose DataContext
        // is used as the starting point for the evaluation of the BindingExpression Path.
        //      We should not store a strong reference to the context element, 
        // for the same reasons as mentioned above for TargetElement.  Instead,
        // we store a weak reference.  Callers should be prepared for the case 
        // ContextElement==null, which is different from _ctxElement==null.  The 
        // former means the BindingExpression uses a context element, but that element has
        // been GC'd;  the latter means that the BindingExpression does not use a context 
        // element.
        internal DependencyObject ContextElement
        {
            get 
            {
                if (_ctxElement != null) 
                    return _ctxElement.Target as DependencyObject; 
                else
                    return null; 
            }
        }

        // The CollectionViewSource is the source object, as a CollectionViewSource. 
        internal CollectionViewSource CollectionViewSource
        { 
            get { return (CollectionViewSource)GetReference(_collectionViewSource); } 
            set { _collectionViewSource = CreateReference(value); }
        } 

        ///  True if this binding expression should ignore changes from the source 
        internal bool IgnoreSourcePropertyChange
        { 
            get
            { 
                if (IsTransferPending) 
                    return true;
 
                if (IsInUpdate)
                {
                    // allow changes from an update to flow back to
                    // the target if there's a converter and the binding 
                    // isn't in "immediate" mode (bug 1207214)
                    return (Converter == null || IsUpdateOnPropertyChanged); 
                } 

                return false; 
            }
        }

        internal PropertyPath Path 
        {
            get { return ParentBinding.Path; } 
        } 

        internal IValueConverter Converter 
        {
            get { return _valueConverter; }
            set { _valueConverter = value; }
        } 

        // MultiBinding looks at this to find out what type its MultiValueConverter should 
        // convert back to, when this BindingExpression is not using a user-specified converter. 
        internal Type ConverterSourceType
        { 
            get { return _sourceType; }
        }

        //------------------------------------------------------ 
        //
        //  Internal Methods 
        // 
        //-----------------------------------------------------
 
        // Create a new BindingExpression from the given Bind description
        internal static BindingExpression CreateBindingExpression(DependencyObject d,
                                                DependencyProperty dp,
                                                Binding binding, 
                                                BindingExpressionBase parent)
        { 
            FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata; 

            if ((fwMetaData != null && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly) 
                throw new ArgumentException(SR.Get(SRID.PropertyNotBindable, dp.Name), "dp");

            // create the BindingExpression
            BindingExpression bindExpr = new BindingExpression(binding, parent); 

            bindExpr.ResolvePropertyDefaultSettings(binding.Mode, binding.UpdateSourceTrigger, fwMetaData); 
 
            // Two-way Binding with an empty path makes no sense
            if (bindExpr.IsReflective && binding.XPath == null && 
                    (binding.Path == null || String.IsNullOrEmpty(binding.Path.Path)))
                throw new InvalidOperationException(SR.Get(SRID.TwoWayBindingNeedsPath));

            return bindExpr; 
        }
 
 
        // Note: For Nullable types, DefaultValueConverter is created for the inner type of the Nullable.
        //       Nullable "Drill-down" service is not provided for user provided Converters. 
        internal void SetupDefaultValueConverter(Type type)
        {
            if (!UseDefaultValueConverter)
                return; 

            if (IsInMultiBindingExpression) 
            { 
                Converter = null;
                _sourceType = type; 
            }
            else if (type != null && type != _sourceType)
            {
                _sourceType = type; 

                Converter = Engine.GetDefaultValueConverter(_sourceType, 
                                    TargetProperty.PropertyType, IsReflective); 

                // null converter means failure to create one 
                if (Converter == null && TraceData.IsEnabled)
                {
                     TraceData.Trace(TraceEventType.Error,
                                    TraceData.CannotCreateDefaultValueConverter( 
                                        _sourceType,
                                        TargetProperty.PropertyType, 
                                        (IsReflective ? "two-way" : "one-way")), 
                                    this );
                } 

                if (Converter == DefaultValueConverter.ValueConverterNotNeeded)
                {
                    Converter = null;     // everyone else takes null for an answer. 
                }
            } 
        } 

        // return true if DataContext is set locally (not inherited) on DependencyObject 
        internal static bool HasLocalDataContext(DependencyObject d)
        {
            return (d.ReadLocalValue(FrameworkElement.DataContextProperty) != DependencyProperty.UnsetValue);
        } 

        //------------------------------------------------------ 
        // 
        //  Private Properties
        // 
        //-----------------------------------------------------

        private bool CanActivate
        { 
            get { return Status != BindingStatus.Unattached; }
        } 
 
        private BindingWorker Worker { get { return _worker; } }
 
        private DynamicValueConverter DynamicConverter
        {
            get
            { 
                if (_dynamicConverter == null)
                { 
                    Invariant.Assert(Worker != null); 
                    // pass along the static source and target types to find same DefaultValueConverter as SetupDefaultValueConverter
                    _dynamicConverter = new DynamicValueConverter(IsReflective, Worker.SourcePropertyType, Worker.TargetPropertyType); 
                }
                return _dynamicConverter;
            }
        } 

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

#region Attachment 

        ///  
        /// Attach the binding expression to the given target object and property. 
        /// 
        internal override void AttachOverride(DependencyObject target, DependencyProperty dp) 
        {
            base.AttachOverride(target, dp);

            // listen for InheritanceContext change (if target is mentored) 
            if (ParentBinding.SourceReference == null || ParentBinding.SourceReference.UsesMentor)
            { 
                DependencyObject mentor = Helper.FindMentor(target); 
                if (mentor != target)
                { 
                    InheritanceContextChangedEventManager.AddListener(target, this);
                    UsingMentor = true;

                    if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Attach)) 
                    {
                        TraceData.Trace(TraceEventType.Warning, 
                                            TraceData.UseMentor( 
                                                TraceData.Identify(this),
                                                TraceData.Identify(mentor))); 
                    }
                }
            }
 
            // listen for lost focus
            if (IsUpdateOnLostFocus) 
            { 
                Invariant.Assert(!IsInMultiBindingExpression, "Source BindingExpressions of a MultiBindingExpression should never be UpdateOnLostFocus.");
                LostFocusEventManager.AddListener(target, this); 
            }

            // attach to things that need tree context.  Do it synchronously
            // if possible, otherwise post a task.  This gives the parser et al. 
            // a chance to assemble the tree before we start walking it.
            AttachToContext(AttachAttempt.First); 
            if (Status == BindingStatus.Unattached) 
            {
                if (TraceLog != null) 
                {
                    string path = (ParentBinding.Path != null) ? ParentBinding.Path.Path : null;
                    TraceLog.Add("Defer attach to {0} of {1}, path = {2}  xpath = {3}",
                        dp.Name, TraceLog.IdFor(target), path, ParentBinding.XPath); 
                }
                Engine.AddTask(this, TaskOps.AttachToContext); 
 
                if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.AttachToContext))
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.DeferAttachToContext(
                                            TraceData.Identify(this)));
                } 
            }
 
            GC.KeepAlive(target);   // keep target alive during activation (bug 956831) 
        }
 

        /// 
        /// Detach the binding expression from its target object and property.
        ///  
        internal override void DetachOverride()
        { 
            if (TraceLog != null) 
            {
                TraceLog.Add("Detaching.  status = {0} {1}", Status, new StackTrace()); 
            }

            Deactivate();
 
            DetachFromContext();
 
            // detach from target element 
            if (IsUpdateOnLostFocus)
            { 
                LostFocusEventManager.RemoveListener(TargetElement, this);
            }

            ChangeValue(DependencyProperty.UnsetValue, false); 

            base.DetachOverride(); 
        } 

        // try to get information from the tree context (parent, root, etc.) 
        // If everything succeeds, activate the binding.
        // If anything fails in a way that might succeed after further layout,
        // just return (with status == Unattached).  The binding engine will try
        // again later. For hard failures, set an error status;  no more chances. 
        // During the "last chance" attempt, treat all failures as "hard".
        void AttachToContext(AttachAttempt attempt) 
        { 
            // if the target has been GC'd, just give up
            DependencyObject target = TargetElement; 
            if (target == null)
                return;     // status will be Detached

            if (TraceLog != null) 
            {
                TraceLog.Add("AttachToContext target = {0}, attempt = {1}", TraceLog.IdFor(target), attempt); 
            } 

            bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.AttachToContext); 
            bool traceObjectRef = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.SourceLookup);

            // certain features should never be tried on the first attempt, as
            // they certainly require at least one layout pass 
            if (attempt == AttachAttempt.First)
            { 
                // relative source with ancestor lookup 
                ObjectRef or = ParentBinding.SourceReference;
                if (or != null && or.TreeContextIsRequired(target)) 
                {
                    if (isExtendedTraceEnabled)
                    {
                        TraceData.Trace(TraceEventType.Warning, 
                                            TraceData.SourceRequiresTreeContext(
                                                TraceData.Identify(this), 
                                                or.Identify())); 
                    }
 
                    return;
                }
            }
 
            bool lastChance = (attempt == AttachAttempt.Last);
 
            if (isExtendedTraceEnabled) 
            {
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.AttachToContext(
                                        TraceData.Identify(this),
                                        lastChance ? " (last chance)" : String.Empty));
            } 

            // if the path has unresolved type names, the parser needs namesapce 
            // information to resolve them.  See XmlTypeMapper.GetTypeFromName. 
            // Ignore this requirement during the last chance, and just let
            // GetTypeFromName fail if it wants to. 
            if (!lastChance && ParentBinding.TreeContextIsRequired)
            {
                if (target.GetValue(XmlAttributeProperties.XmlnsDictionaryProperty) == null ||
                    target.GetValue(XmlAttributeProperties.XmlNamespaceMapsProperty) == null) 
                {
                    if (isExtendedTraceEnabled) 
                    { 
                        TraceData.Trace(TraceEventType.Warning,
                                            TraceData.PathRequiresTreeContext( 
                                                TraceData.Identify(this),
                                                ParentBinding.Path.Path));
                    }
 
                    return;
                } 
            } 

            // if the binding uses a mentor, check that it exists 
            DependencyObject mentor = !UsingMentor ? target :  Helper.FindMentor(target);
            if (mentor == null)
            {
                if (isExtendedTraceEnabled) 
                {
                    TraceData.Trace(TraceEventType.Warning, 
                                        TraceData.NoMentorExtended( 
                                            TraceData.Identify(this)));
                } 

                if (lastChance)
                {
                    SetStatus(BindingStatus.PathError); 
                    if (TraceData.IsEnabled)
                    { 
                        TraceData.Trace(TraceEventType.Error, TraceData.NoMentor, this); 
                    }
                } 
                return;
            }

            // determine the element whose DataContext governs this BindingExpression 
            DependencyObject contextElement = null;     // no context element
            bool contextElementFound = true; 
            if (ParentBinding.SourceReference == null) 
            {
                contextElement = mentor;    // usually the mentor/target element 

                // special cases:
                // 1. if target property is DataContext, use the target's parent.
                //      This enables  and 
                // 2. if the target is ContentPresenter and the target property
                //      is Content, use the parent.  This enables 
                //           
                // 3. if target is CVS, and its inheritance context was set
                //      via DataContext, use the mentor's parent.  This enables 
                //       
                CollectionViewSource cvs;
                if (TargetProperty == FrameworkElement.DataContextProperty ||
                    (TargetProperty == ContentPresenter.ContentProperty && 
                            target is ContentPresenter) ||
                    (UsingMentor && 
                            (cvs = target as CollectionViewSource) != null && 
                            cvs.PropertyForInheritanceContext == FrameworkElement.DataContextProperty)
                    ) 
                {
                    contextElement = FrameworkElement.GetFrameworkParent(contextElement);
                    contextElementFound = (contextElement != null);
                } 
            }
            else 
            { 
                RelativeObjectRef ror = ParentBinding.SourceReference as RelativeObjectRef;
                if (ror != null && ror.ReturnsDataContext) 
                {
                    object o = ror.GetObject(mentor, traceObjectRef);
                    contextElement = o as DependencyObject;    // ref to another element's DataContext
                    contextElementFound = (o != DependencyProperty.UnsetValue); 
                }
            } 
 
            if (isExtendedTraceEnabled)
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.ContextElement(
                                        TraceData.Identify(this),
                                        TraceData.Identify(contextElement), 
                                        contextElementFound ? "OK" : "error"));
            } 
 
            // if we need a context element, check that we found it
            if (!contextElementFound) 
            {
                if (lastChance)
                {
                    SetStatus(BindingStatus.PathError); 
                    if (TraceData.IsEnabled)
                    { 
                        TraceData.Trace(TraceEventType.Error, TraceData.NoDataContext, this); 
                    }
                } 

                return;
            }
 
            // determine the source object, from which the path evaluation starts
            object source; 
            ObjectRef sourceRef; 

            if (contextElement != null) 
            {
                source = contextElement.GetValue(FrameworkElement.DataContextProperty);

                // if the data context is default null, try again later;  future 
                // layout may change the inherited value.
                // Ignore this requirement during the last chance, and just let 
                // the binding to null DataContext proceed. 
                if (source == null && !lastChance && !HasLocalDataContext(contextElement))
                { 
                    if (isExtendedTraceEnabled)
                    {
                        TraceData.Trace(TraceEventType.Warning,
                                            TraceData.NullDataContext( 
                                                TraceData.Identify(this)));
                    } 
 
                    return;
                } 
            }
            else if ((sourceRef = ParentBinding.SourceReference) != null)
            {
                source = sourceRef.GetDataObject(mentor, traceObjectRef, ResolveNamesInTemplate); 

                // check that the source could be found 
                if (source == DependencyProperty.UnsetValue) 
                {
                    if (lastChance) 
                    {
                        SetStatus(BindingStatus.PathError);
                        if (TraceData.IsEnabled)
                        { 
                            TraceData.Trace(TraceLevel, TraceData.NoSource(sourceRef), this);
                        } 
                    } 

                    return; 
                }
            }
            else
            { 
                // we get here only if we need ambient data context, but there
                // is no context element.  E.g. binding the DataContext property 
                // of an element with no parent.  Just use null. 
                source = null;
            } 

            // if we get this far, all the ingredients for a successful binding
            // are present.  Remember what we've found and activate the binding.
            if (contextElement != null) 
                _ctxElement = new WeakReference(contextElement);
 
            // attach to context element 
            ChangeWorkerSources(null, 0);
 
            if (!UseDefaultValueConverter)
            {
                _valueConverter = ParentBinding.Converter;
 
                if (_valueConverter == null)
                { 
                    throw new InvalidOperationException(SR.Get(SRID.MissingValueConverter)); // report instead of throw? 
                }
            } 

            SetStatus(BindingStatus.Inactive);

            // inner BindingExpressions of PriorityBindingExpressions may not need to be activated 
            if (IsInPriorityBindingExpression)
                ParentPriorityBindingExpression.InvalidateChild(this); 
            else    // singular BindingExpressions and those in MultiBindingExpressions should always activate 
                Activate(source);
 
            GC.KeepAlive(target);   // keep target alive during activation (bug 956831)
        }

        // Detach from things that may require tree context 
        private void DetachFromContext()
        { 
            // detach from data source 
            if (_dataProvider != null)
            { 
                if (TraceLog != null)
                {
                    TraceLog.Add("-OnDataChanged to {0}", TraceLog.IdFor(_dataProvider));
                } 
                DataChangedEventManager.RemoveListener(_dataProvider, this);
            } 
 
            if (!UseDefaultValueConverter)
            { 
                _valueConverter = null;
            }

            if (!IsInBindingExpressionCollection) 
                ChangeSources(null);
 
            if (UsingMentor) 
            {
                DependencyObject target = TargetElement; 
                if (target != null)
                    InheritanceContextChangedEventManager.RemoveListener(target, this);
            }
 
            _ctxElement = null;
        } 
 
#endregion Attachment
 
#region Activation

        // Activate the BindingExpression, if necessary and possible
        internal override void Activate() 
        {
            if (!CanActivate) 
                return; 

            if (_ctxElement == null) 
            {
                // only activate once if there's an explicit source
                if (Status == BindingStatus.Inactive)
                { 
                    DependencyObject target = TargetElement;
                    if (target != null) 
                    { 
                        if (UsingMentor)
                        { 
                            target = Helper.FindMentor(target);
                            if (target == null)
                            {
                                // mentor is not available 
                                SetStatus(BindingStatus.PathError);
                                if (TraceData.IsEnabled) 
                                { 
                                    TraceData.Trace(TraceEventType.Error, TraceData.NoMentor, this);
                                } 
                                return;
                            }
                        }
                        Activate(ParentBinding.SourceReference.GetDataObject(target, ResolveNamesInTemplate, false)); 
                    }
                } 
            } 
            else
            { 
                DependencyObject contextElement = ContextElement;
                if (contextElement == null)
                {
                    // context element has been GC'd, or unavailable (e.g. no mentor) 
                    SetStatus(BindingStatus.PathError);
                    if (TraceData.IsEnabled) 
                    { 
                        TraceData.Trace(TraceEventType.Error, TraceData.NoDataContext, this);
                    } 
                    return;
                }

                object item = contextElement.GetValue(FrameworkElement.DataContextProperty); 

                // if binding inactive or the data item has changed, (re-)activate 
                if (Status == BindingStatus.Inactive || !Object.Equals(item, DataItem)) 
                {
                    Activate(item); 
                }
            }
        }
 
        internal void Activate(object item)
        { 
            DependencyObject target = TargetElement; 
            if (target == null)
                return; 

            bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Activate);

            Deactivate(); 

            if (TraceLog != null) 
                TraceLog.Add("Activate item = {0}", TraceLog.IdFor(item)); 

            CollectionViewSource cvs = item as CollectionViewSource; 
            this.CollectionViewSource = cvs;
            if (cvs != null)
            {
                // when the source is CollectionViewSource, use its view instead 
                item = cvs.CollectionView;
 
                // the CVS is one of our implicit sources 
                ChangeWorkerSources(null, 0);
 
                if (isExtendedTraceEnabled)
                {
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.UseCVS( 
                                            TraceData.Identify(this),
                                            TraceData.Identify(cvs))); 
                } 
            }
            else 
            {
                // when the source is DataSourceProvider, use its data instead
                item = DereferenceDataProvider(item);
            } 

            _dataItem = CreateReference(item); 
 
            if (isExtendedTraceEnabled)
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.ActivateItem(
                                        TraceData.Identify(this),
                                        TraceData.Identify(item))); 
            }
 
            if (Worker == null) 
                CreateWorker();
 
            // mark the BindingExpression active
            SetStatus(BindingStatus.Active);

            // attach to data item (may set error status) 
            Worker.AttachDataItem();
 
            // 

 
            // initial transfer
            if (!IsOneWayToSource)
            {
                TransferValue(); 
            }
            else 
            { 
                UpdateValue();
            } 

            GC.KeepAlive(target);   // keep target alive during activation (bug 956831)
        }
 
        internal override void Deactivate()
        { 
            if (TraceLog != null) 
                TraceLog.Add("Deactivate");
 
            // inactive BindingExpressions don't need any more work
            if (Status == BindingStatus.Inactive)
                return;
 
            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Activate))
            { 
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.Deactivate(
                                        TraceData.Identify(this))); 
            }

            // stop transfers
            CancelPendingTasks(); 

            // detach from data item 
            if (Worker != null) 
                Worker.DetachDataItem();
 
            // restore default value, in case source/converter fail to provide a good value
            ChangeValue(DefaultValueObject, false);

            // don't keep a handle to old data item if the BindingExpression is inactive 
            _dataItem = null;
 
            SetStatus(BindingStatus.Inactive); 
        }
 
        // if the root item is a DataSourceProvider, use its Data instead
        // and listen for DataChanged events.  (Unless overridden explicitly
        // by the BindsDirectlyToSource property).
        private object DereferenceDataProvider(object item) 
        {
            if (ParentBinding.BindsDirectlyToSource) 
                return item; 

            DataSourceProvider dataProvider = item as DataSourceProvider; 
            if (dataProvider != _dataProvider)
            {
                // we have a new data provider - retarget the event handler
                if (_dataProvider != null) 
                {
                    if (TraceLog != null) 
                    { 
                        TraceLog.Add("-OnDataChanged to {0}", TraceLog.IdFor(_dataProvider));
                    } 
                    DataChangedEventManager.RemoveListener(_dataProvider, this);
                }

                _dataProvider = dataProvider; 

                if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Activate)) 
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.UseDataProvider( 
                                            TraceData.Identify(this),
                                            TraceData.Identify(_dataProvider)));
                }
 
                if (_dataProvider != null)
                { 
                    if (TraceLog != null) 
                    {
                        TraceLog.Add("+OnDataChanged to {0}", TraceLog.IdFor(_dataProvider)); 
                    }
                    DataChangedEventManager.AddListener(_dataProvider, this);
                    _dataProvider.InitialLoad();
                } 
            }
 
            return (_dataProvider != null) ? _dataProvider.Data : item; 
        }
 
#endregion Activation

#region Worker
 
        private void CreateWorker()
        { 
            Invariant.Assert(Worker == null, "duplicate call to CreateWorker"); 

            _worker = new ClrBindingWorker(this, Engine); 
        }

        // worker calls here if it changes its dependency sources
        // n is the number of real entries in newWorkerSources (which may be longer) 
        internal void ChangeWorkerSources(WeakDependencySource[] newWorkerSources, int n)
        { 
            int offset = 0; 
            int size = n;
 
            // create the new sources array, and add the context and CollectionViewSource elements
            DependencyObject contextElement = ContextElement;
            CollectionViewSource cvs = CollectionViewSource;
 
            if (contextElement != null)
                ++size; 
            if (cvs != null) 
                ++size;
 
            WeakDependencySource[] newSources = (size > 0) ? new WeakDependencySource[size] : null;

            if (contextElement != null)
            { 
                newSources[offset++] = new WeakDependencySource(_ctxElement, FrameworkElement.DataContextProperty);
            } 
 
            if (cvs != null)
            { 
                WeakReference wr = _collectionViewSource as WeakReference;
                newSources[offset++] =
                    (wr != null) ? new WeakDependencySource(wr, CollectionViewSource.ViewProperty)
                                 : new WeakDependencySource(cvs, CollectionViewSource.ViewProperty); 
            }
 
            // add the worker's sources 
            if (n > 0)
                Array.Copy(newWorkerSources, 0, newSources, offset, n); 

            // tell the property engine
            ChangeSources(newSources);
        } 

#endregion Worker 
 
#region Value
 
        // transfer a value from the source to the target
        void TransferValue()
        {
            TransferValue(NullDataItem, false); 
        }
 
        internal void TransferValue(object newValue, bool isASubPropertyChange) 
        {
            // 



 
            // if the target element has been GC'd, do nothing
            DependencyObject target = TargetElement; 
            if (target == null) 
                return;
 
            // if the BindingExpression hasn't activated, do nothing
            if (Worker == null)
                return;
 
            bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Transfer);
 
            // clear the Pending flag before actually doing the transfer.  That way if another 
            // thread sets the flag, we'll schedule another transfer.  This might do more
            // transfers than absolutely necessary, but it guarantees that we'll eventually pick 
            // up the value from the last change.
            IsTransferPending = false;
            IsInTransfer = true;
 
            UsingFallbackValue = false;
 
            object value = (newValue == NullDataItem) ? Worker.RawValue() : newValue; 

            if (isExtendedTraceEnabled) 
            {
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.GetRawValue(
                                        TraceData.Identify(this), 
                                        TraceData.Identify(value)));
            } 
 
            // For DBNull, unless there's a user converter, we handle it here
            if ((value == DBNull.Value) && (Converter == null || UseDefaultValueConverter)) 
            {
                Type type = TargetProperty.PropertyType;
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                { 
                    value = null;
                } 
                else 
                {
                    value = DependencyProperty.UnsetValue; 
                }

                if (isExtendedTraceEnabled)
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.ConvertDBNull( 
                                            TraceData.Identify(this), 
                                            TraceData.Identify(value)));
                } 
            }

            // ELSE apply the converter, if available
            else if (value != DependencyProperty.UnsetValue && Converter != null) 
            {
                CultureInfo culture = GetCulture(); 
 
                if (!UseDefaultValueConverter)
                { 
                    Type targetType = TargetProperty.PropertyType;
                    // if there's a user-defined converter, call it without catching
                    // exceptions (bug 992237).  It can return DependencyProperty.UnsetValue
                    // to indicate a failure to convert. 
                    value = Converter.Convert(value, targetType, ParentBinding.ConverterParameter, culture);
 
                    if (isExtendedTraceEnabled) 
                    {
                        TraceData.Trace(TraceEventType.Warning, 
                                            TraceData.UserConverter(
                                                TraceData.Identify(this),
                                                TraceData.Identify(value)));
                    } 

                    // chain in a default value converter if the returned value's type is not compatible with the targetType 
                    if (   ((value != null) && (value != Binding.DoNothing) && (value != DependencyProperty.UnsetValue)) 
                        && !targetType.IsAssignableFrom(value.GetType()))
                    { 
                        // the dynamic converter is shared between Transfer and Update directions
                        // once instantiated, DefaultValueConverters are kept in a lookup table, making swapping
                        // default value converters in the DynamicValueConverter reasonably fast
                        // here we pass in the TargetElement, see below NOTE: 
                        value = ConvertHelper(DynamicConverter, value, targetType, this.TargetElement, culture);
 
                        if (isExtendedTraceEnabled) 
                        {
                            TraceData.Trace(TraceEventType.Warning, 
                                                TraceData.ChainedConverter(
                                                    TraceData.Identify(this),
                                                    TraceData.Identify(value)));
                        } 
                    }
                } 
                else 
                {
                    // call a DefaultValueConverter: 
                    // NOTE:
                    // here we pass in the TargetElement that is expected by our default value converters;
                    // this does violate the general rule that value converters should be stateless
                    // and must not be aware of e.g. their target element. 
                    // Our DefaultValueConverters are all internal and only use this target element
                    // to determine a BaseUri for their TypeConverters 
                    // -> hence a reluctant exeption of above rule 
                    value = ConvertHelper(Converter, value, TargetProperty.PropertyType, this.TargetElement, culture);
 
                    if (isExtendedTraceEnabled)
                    {
                        TraceData.Trace(TraceEventType.Warning,
                                            TraceData.DefaultConverter( 
                                                TraceData.Identify(this),
                                                TraceData.Identify(value))); 
                    } 
                }
 
                // the special value DoNothing means no error, but no data transfer
                if (value == Binding.DoNothing)
                    goto Done;
 
                if (value == DependencyProperty.UnsetValue)
                    SetStatus(BindingStatus.UpdateTargetError); 
            } 

            // if the value isn't acceptable to the target property, don't use it 
            // (in MultiBinding, the value will go through the multi-converter, so
            // it's too early to make this judgment)
            if (!IsInMultiBindingExpression && value != IgnoreDefaultValue &&
                value != DependencyProperty.UnsetValue && !TargetProperty.IsValidValue(value)) 
            {
                if (TraceData.IsEnabled && !IsInBindingExpressionCollection) 
                { 
                    TraceData.Trace(TraceLevel, TraceData.BadValueAtTransfer, value, this);
                } 

                if (isExtendedTraceEnabled)
                {
                    TraceData.Trace(TraceEventType.Warning, 
                                        TraceData.BadValueAtTransferExtended(
                                            TraceData.Identify(this), 
                                            TraceData.Identify(value))); 
                }
 
                value = DependencyProperty.UnsetValue;

                if (Status == BindingStatus.Active)
                    SetStatus(BindingStatus.UpdateTargetError); 
            }
 
            // If we haven't obtained a value yet, 
            // use the fallback value.  This could happen when the currency
            // has moved off the end of the collection, e.g. 
            if (value == DependencyProperty.UnsetValue)
            {
                value = UseFallbackValue();
 
                if (isExtendedTraceEnabled)
                { 
                    TraceData.Trace(TraceEventType.Warning, 
                                        TraceData.UseFallback(
                                            TraceData.Identify(this), 
                                            TraceData.Identify(value)));
                }
            }
 
            // Ignore a default source value by setting the value to NoValue;
            // this causes the property engine to obtain the value elsewhere 
            if (value == IgnoreDefaultValue) 
            {
                value = Expression.NoValue; 
            }

            if (isExtendedTraceEnabled)
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.TransferValue( 
                                        TraceData.Identify(this), 
                                        TraceData.Identify(value)));
            } 

            // update the cached value
            ChangeValue(value, true);
            Invalidate(isASubPropertyChange); 
            OnTargetUpdated();
            CheckDataErrors(); 
 
        Done:
            IsInTransfer = false; 

            GC.KeepAlive(target);   // keep target alive during transfer (bug 956831)
        }
 
        private void CheckDataErrors()
        { 
            // update the validation state 
            ValidationError validationError = null;
            if (ValidatesOnDataErrors) 
            {
                validationError = Worker.ValidateDataError(this);
            }
            UpdateValidationError(validationError); 
        }
 
        private object ConvertHelper(IValueConverter converter, object value, Type targetType, object parameter, CultureInfo culture) 
        {
            Invariant.Assert(converter != null); 
            // 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 complains about catching NullReference (and other) exceptions.
            // It doesn't recognize that IsCriticalException() handles these correctly. 
            #pragma warning disable 56500 

            object convertedValue = null; 
            try
            {
                convertedValue = converter.Convert(value, targetType, parameter, culture);
            } 

            // Catch all exceptions.  There is no app code on the stack, 
            // so the exception isn't actionable by the app. 
            // Yet we don't want to crash the app.
            catch (Exception ex) 
            {
                // the DefaultValueConverter can end up calling BaseUriHelper.GetBaseUri()
                // which can raise SecurityException if the app does not have the right FileIO privileges
                if (CriticalExceptions.IsCriticalException(ex)) 
                    throw;
 
                if (TraceData.IsEnabled) 
                {
                    TraceData.Trace(TraceLevel, 
                            TraceData.BadConverterForTransfer(
                                converter.GetType().Name,
                                AvTrace.ToStringHelper(value),
                                AvTrace.TypeName(value)), 
                            this, ex);
                } 
                convertedValue = DependencyProperty.UnsetValue; 
            }
            catch // non CLS compliant exception 
            {
                if (TraceData.IsEnabled)
                {
                    TraceData.Trace(TraceLevel, 
                            TraceData.BadConverterForTransfer(
                                converter.GetType().Name, 
                                AvTrace.ToStringHelper(value), 
                                AvTrace.TypeName(value)),
                            this); 
                }
                convertedValue = DependencyProperty.UnsetValue;
            }
 
            #pragma warning restore 56500
            #pragma warning restore 1634, 1691 
 
            return convertedValue;
        } 

        private object ConvertBackHelper(IValueConverter converter,
                                         object value,
                                         Type sourceType, 
                                         object parameter,
                                         CultureInfo culture) 
        { 
            Invariant.Assert(converter != null);
 
            // 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 complains about catching NullReference (and other) exceptions.
            // It doesn't recognize that IsCriticalException() handles these correctly. 
            #pragma warning disable 56500 

            object convertedValue = null; 
            try
            {
                convertedValue = converter.ConvertBack(value, sourceType, parameter, culture);
            } 

            // Catch all exceptions.  There is no app code on the stack, 
            // so the exception isn't actionable by the app. 
            // Yet we don't want to crash the app.
            catch (Exception ex) 
            {
                // the DefaultValueConverter can end up calling BaseUriHelper.GetBaseUri()
                // which can raise SecurityException if the app does not have the right FileIO privileges
                if (CriticalExceptions.IsCriticalException(ex)) 
                    throw;
 
                if (TraceData.IsEnabled) 
                {
                    TraceData.Trace(TraceEventType.Error, 
                        TraceData.BadConverterForUpdate(
                            AvTrace.ToStringHelper(Value),
                            AvTrace.TypeName(value)),
                        this, ex); 
                }
 
                ProcessException(ex); 
                convertedValue = DependencyProperty.UnsetValue;
            } 
            catch // non CLS compliant exception
            {
                if (TraceData.IsEnabled)
                { 
                    TraceData.Trace(TraceEventType.Error,
                        TraceData.BadConverterForUpdate( 
                            AvTrace.ToStringHelper(Value), 
                            AvTrace.TypeName(value)),
                        this); 
                }
                convertedValue = DependencyProperty.UnsetValue;
            }
 
            #pragma warning restore 56500
            #pragma warning restore 1634, 1691 
 
            return convertedValue;
        } 

        internal void ScheduleTransfer(bool isASubPropertyChange)
        {
            if (isASubPropertyChange && Converter != null) 
            {
                // a converter doesn't care about sub-property changes 
                isASubPropertyChange = false; 
            }
 
            TransferValue(NullDataItem, isASubPropertyChange);
        }

 
        void OnTargetUpdated()
        { 
            if (NotifyOnTargetUpdated) 
            {
                DependencyObject target = TargetElement; 
                if (target != null)
                {
                    if (    !IsInMultiBindingExpression           // not an inner BindingExpression
                        &&  (   !IsInPriorityBindingExpression 
                            ||  this == ParentPriorityBindingExpression.ActiveBindingExpression))   // not an inactive BindingExpression
                    { 
                        // while attaching a normal (not style-defined) BindingExpression, 
                        // we must defer raising the event until after the
                        // property has been invalidated, so that the event handler 
                        // gets the right value if it asks (bug 1036862)
                        if (IsAttaching && this == target.ReadLocalValue(TargetProperty))
                        {
                            Engine.AddTask(this, TaskOps.RaiseTargetUpdatedEvent); 
                        }
                        else 
                        { 
                            OnTargetUpdated(target, TargetProperty);
                        } 
                    }
                }
            }
        } 

        void OnSourceUpdated() 
        { 
            if (NotifyOnSourceUpdated)
            { 
                DependencyObject target = TargetElement;
                if (target != null)
                {
                    if (    !IsInMultiBindingExpression           // not an inner BindingExpression 
                        &&  (   !IsInPriorityBindingExpression
                            ||  this == ParentPriorityBindingExpression.ActiveBindingExpression))   // not an inactive BindingExpression 
                    { 
                        OnSourceUpdated(target, TargetProperty);
                    } 
                }
            }
        }
 

 
        internal override void Update(bool synchronous) 
        {
            // various reasons not to update: 
            if (   !NeedsUpdate                     // nothing to do
                || !IsReflective                    // no update desired
                || IsInTransfer                     // in a transfer
                || Worker == null                   // not activated 
                || !Worker.CanUpdate                // no source (currency moved off end)
                ) 
                return; 

            if (synchronous) 
            {
                UpdateValue();
            }
            else 
            {
                Engine.AddTask(this, TaskOps.UpdateValue); 
            } 
        }
 
        void UpdateValue()
        {
            object value = Value;
            Collection validationRules = ParentBinding.ValidationRulesInternal; 
            CultureInfo culture = GetCulture();
 
            bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Update); 
            if (isExtendedTraceEnabled)
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.UpdateRawValue(
                                        TraceData.Identify(this),
                                        TraceData.Identify(value))); 
            }
 
            UpdateValidationError(null); 

            if (validationRules != null) 
            {
                foreach(ValidationRule validationRule in validationRules)
                {
                    ValidationResult validationResult = validationRule.Validate(value, culture); 

                    if (!validationResult.IsValid) 
                    { 
                        if (isExtendedTraceEnabled)
                        { 
                            TraceData.Trace(TraceEventType.Warning,
                                                TraceData.ValidationRuleFailed(
                                                    TraceData.Identify(this),
                                                    TraceData.Identify(validationRule))); 
                        }
 
                        UpdateValidationError( new ValidationError(validationRule, this, validationResult.ErrorContent, null)); 
                        return; // [....]:
                    } 
                }
            }

            if (Converter != null) 
            {
                if (!UseDefaultValueConverter) 
                { 
                    Type sourceType = Worker.SourcePropertyType;
                    // if there's a user-defined converter, call it without catching 
                    // exceptions (bug 992237).  It can return DependencyProperty.UnsetValue
                    // to indicate a failure to convert.
                    value = Converter.ConvertBack(value, sourceType, ParentBinding.ConverterParameter, culture);
 
                    if (isExtendedTraceEnabled)
                    { 
                        TraceData.Trace(TraceEventType.Warning, 
                                            TraceData.UserConvertBack(
                                                TraceData.Identify(this), 
                                                TraceData.Identify(value)));
                    }

                    // chain in a default value converter if the returned value's type is not compatible with the sourceType 
                    if ( (value != Binding.DoNothing) && (value != DependencyProperty.UnsetValue) &&
                        !IsValidValueForUpdate(value, sourceType) ) 
                    { 
                        // the dynamic converter is shared between Transfer and Update directions
                        // once instantiated, DefaultValueConverters are kept in a lookup table, making swapping 
                        // default value converters reasonably fast
                        // here we pass in the TargetElement, see NOTE of caution in TransferValue() why this is ok
                        value = ConvertBackHelper(DynamicConverter, value, sourceType, this.TargetElement, culture);
 
                        if (isExtendedTraceEnabled)
                        { 
                            TraceData.Trace(TraceEventType.Warning, 
                                                TraceData.ChainedConvertBack(
                                                    TraceData.Identify(this), 
                                                    TraceData.Identify(value)));
                        }
                    }
                } 
                else
                { 
                    // here we pass in the TargetElement, see NOTE of caution in TransferValue() why this is ok 
                    value = ConvertBackHelper(Converter, value, Worker.SourcePropertyType, this.TargetElement, culture);
 
                    if (isExtendedTraceEnabled)
                    {
                        TraceData.Trace(TraceEventType.Warning,
                                            TraceData.DefaultConvertBack( 
                                                TraceData.Identify(this),
                                                TraceData.Identify(value))); 
                    } 
                }
            } 

            if (isExtendedTraceEnabled)
            {
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.Update(
                                        TraceData.Identify(this), 
                                        TraceData.Identify(value))); 
            }
 
            // If there is a failure to convert, then Update failed.
            if (value == DependencyProperty.UnsetValue)
            {
                SetStatus(BindingStatus.UpdateSourceError); 
            }
 
            if (value == Binding.DoNothing || value == DependencyProperty.UnsetValue) 
            {
                EndSourceUpdate(); 
                return;
            }

 
            // 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 complains about catching NullReference (and other) exceptions. 
            // It doesn't recognize that IsCriticalException() handles these correctly.
            #pragma warning disable 56500

            try 
            {
                BeginSourceUpdate(); 
                Worker.UpdateValue(value); 
                CheckDataErrors();
            } 

            // Catch all exceptions.  There is no app code on the stack,
            // so the exception isn't actionable by the app.
            // Yet we don't want to crash the app. 
            catch (Exception ex)
            { 
                if (CriticalExceptions.IsCriticalException(ex)) 
                    throw;
 
                if (TraceData.IsEnabled)
                    TraceData.Trace(TraceEventType.Error, TraceData.WorkerUpdateFailed, this, ex);

                ProcessException(ex); 
                SetStatus(BindingStatus.UpdateSourceError);
            } 
            catch // non CLS compliant exception 
            {
                if (TraceData.IsEnabled) 
                    TraceData.Trace(TraceEventType.Error, TraceData.WorkerUpdateFailed, this);

                SetStatus(BindingStatus.UpdateSourceError);
            } 
            finally
            { 
                EndSourceUpdate(); 
            }
 
            #pragma warning restore 56500
            #pragma warning restore 1634, 1691

            OnSourceUpdated(); 
        }
 
        private bool IsValidValueForUpdate(object value, Type sourceType) 
        {
            // null is always valid, even for value types.  The reflection layer 
            // apparently converts null to default(T).
            if (value == null)
                return true;
 
            // if direct assignment is possible, the value is valid
            if (sourceType.IsAssignableFrom(value.GetType())) 
                return true; 

            // if the value is DBNull, ask the worker (answer depends on several factors) 
            if (Convert.IsDBNull(value))
                return Worker.IsDBNullValidForUpdate;

            // otherwise the value is invalid 
            return false;
        } 
 
        private void ProcessException(Exception ex)
        { 
            object filteredException = null;
            ValidationError validationError = null;

            // If there is not ExceptionFilter, then Wrap the 
            // exception in a ValidationError.
            if (ExceptionFilterExists()) 
            { 
                filteredException = CallDoFilterException(ex);
 
                if (filteredException == null)
                    return;

                validationError = filteredException as ValidationError; 
            }
 
            // See if an ExceptionValidationRule is in effect 
            if (validationError == null && ValidatesOnExceptions)
            { 
                ValidationRule exceptionValidationRule = ExceptionValidationRule.Instance;

                if (filteredException == null)
                { 
                    validationError = new ValidationError(exceptionValidationRule, this, ex.Message, ex);
                } 
                else 
                {
                    validationError = new ValidationError(exceptionValidationRule, this, filteredException, ex); 
                }
            }

            if (validationError != null) 
            {
                // use MarkInvalid rather than UpdateValidationErrors because 
                // this is essentially an explicit invalidation as this BindingExpression has 
                // already passed all of the declared ValidationRules
                Validation.MarkInvalid(this, validationError); 
            }
        }
#endregion Value
 
#region Event handlers
 
        private void OnDataContextChanged(DependencyObject contextElement) 
        {
            // ADO BindingExpressions change the data context when a field changes. 
            // If the field is the one we're updating, ignore the DC change.
            if (!IsInUpdate && CanActivate)
            {
                object newItem = contextElement.GetValue(FrameworkElement.DataContextProperty); 
                if (!Object.Equals(DataItem, newItem))
                    Activate(newItem); 
            } 
        }
 
        /// 
        /// Handle events from the centralized event table
        /// 
        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) 
        {
            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Events)) 
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.GotEvent( 
                                        TraceData.Identify(this),
                                        TraceData.IdentifyWeakEvent(managerType),
                                        TraceData.Identify(sender)));
            } 

            if (managerType == typeof(CurrentChangingEventManager)) 
            { 
                Update(true);
                // 
            }
            else if (managerType == typeof(CurrentChangedEventManager))
            {
                Worker.OnCurrentChanged(sender as ICollectionView, e); 
            }
            else if (managerType == typeof(DataChangedEventManager)) 
            { 
                if (TraceLog != null)
                { 
                    TraceLog.Add(" OnDataChanged from {0} at {1}", TraceLog.IdFor(_dataProvider), TraceLog.IdFor(this));
                }
                Activate(sender);
            } 
            else if (managerType == typeof(LostFocusEventManager))
            { 
                Update(true); 
            }
            else if (managerType == typeof(InheritanceContextChangedEventManager)) 
            {
                if (Status != BindingStatus.Unattached)
                    AttachToContext(AttachAttempt.Last);
            } 
            else
            { 
                return false;       // unrecognized event 
            }
 
            return true;
        }

#endregion Event handlers 

#region Helper functions 
 

        // 
        // If this BindingExpression's ParentBinding has an ExceptionFilter set,
        // call it, otherwise give the MultiBinding (if there is one)
        // a chance.
        // 
        private object CallDoFilterException(Exception ex)
        { 
            if (ParentBinding.UpdateSourceExceptionFilter != null) 
            {
                return ParentBinding.DoFilterException(this, ex); 
            }
            else if (IsInMultiBindingExpression)
            {
                return ParentMultiBindingExpression.ParentMultiBinding.DoFilterException(this, ex); 
            }
 
            return null; 
        }
 
        private bool ExceptionFilterExists()
        {
            return ( (ParentBinding.UpdateSourceExceptionFilter != null) ||
                     (IsInMultiBindingExpression && ParentMultiBindingExpression.ParentMultiBinding.UpdateSourceExceptionFilter != null) 
                   );
        } 
 

        // surround any code that changes the value of a BindingExpression by 
        //      using (bindExpr.ChangingValue())
        //      { ... }
        internal IDisposable ChangingValue()
        { 
            return new ChangingValueHelper(this);
        } 
 
        // cancel any pending work
        internal void CancelPendingTasks() 
        {
            Engine.CancelTasks(this);
        }
 
        // invalidate the target property
        void Invalidate(bool isASubPropertyChange) 
        { 
            // don't invalidate during Attach.  The property engine does it
            // already, and it would interfere with the on-demand activation 
            // of style-defined BindingExpressions.
            if (IsAttaching)
                return;
 
            DependencyObject target = TargetElement;
            if (target != null) 
            { 
                if (IsInBindingExpressionCollection)
                    ParentBindingExpressionBase.InvalidateChild(this); 
                else
                {
                    if (TargetProperty != NoTargetProperty)
                    { 
                        // recompute expression
                        if (!isASubPropertyChange) 
                        { 
                            target.InvalidateProperty(TargetProperty);
                        } 
                        else
                        {
                            target.NotifySubPropertyChange(TargetProperty);
                        } 
                    }
                } 
            } 
        }
 
        // replace this BindingExpression with a new one
        void Replace()
        {
            DependencyObject target = TargetElement; 
            if (target != null)
            { 
                if (IsInBindingExpressionCollection) 
                    ParentBindingExpressionBase.ReplaceChild(this);
                else 
                    BindingOperations.SetBinding(target, TargetProperty, ParentBinding);
            }
        }
 
        // raise the TargetUpdated event (explicit polymorphism)
        internal static void OnTargetUpdated(DependencyObject d, DependencyProperty dp) 
        { 
            DataTransferEventArgs args = new DataTransferEventArgs(d, dp);
            args.RoutedEvent = Binding.TargetUpdatedEvent; 
            FrameworkObject fo = new FrameworkObject(d);

            if (!fo.IsValid && d != null)
            { 
                fo.Reset(Helper.FindMentor(d));
            } 
 
            fo.RaiseEvent(args);
        } 

        // raise the SourceUpdatedEvent event (explicit polymorphism)
        internal static void OnSourceUpdated(DependencyObject d, DependencyProperty dp)
        { 
            DataTransferEventArgs args = new DataTransferEventArgs(d, dp);
            args.RoutedEvent = Binding.SourceUpdatedEvent; 
            FrameworkObject fo = new FrameworkObject(d); 

            if (!fo.IsValid && d != null) 
            {
                fo.Reset(Helper.FindMentor(d));
            }
 
            fo.RaiseEvent(args);
        } 
 
        private object HandlePropertyInvalidationOperation(object o)
        { 
            // This is the case where the source of the Binding belonged to a different Dispatcher
            // than the target. For this scenario the source marshals off the invalidation information
            // onto the target's Dispatcher queue. This is where we unpack the marshalled information
            // to fire the invalidation on the target object. 

            object[] args = (object[])o; 
            HandlePropertyInvalidation((DependencyObject)args[0], (DependencyPropertyChangedEventArgs)args[1]); 
            return null;
        } 

        private void HandlePropertyInvalidation(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            DependencyProperty dp = args.Property; 

            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Events)) 
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.GotPropertyChanged( 
                                        TraceData.Identify(this),
                                        TraceData.Identify(d),
                                        dp.Name));
            } 

            if (dp == FrameworkElement.DataContextProperty) 
            { 
                DependencyObject contextElement = ContextElement;
                if (d == contextElement) 
                {
                    OnDataContextChanged(contextElement);
                }
            } 

            if (dp == CollectionViewSource.ViewProperty) 
            { 
                CollectionViewSource cvs = this.CollectionViewSource;
                if (d == cvs) 
                {
                    Activate(cvs);
                }
            } 

            if (Worker != null) 
            { 
                Worker.OnSourceInvalidation(d, dp, args.IsASubPropertyChange);
            } 
        }


        private class ChangingValueHelper : IDisposable 
        {
            internal ChangingValueHelper(BindingExpression b) 
            { 
                _bindingExpression = b;
                b.CancelPendingTasks(); 
            }

            public void Dispose()
            { 
                _bindingExpression.TransferValue();
            } 
 
            BindingExpression _bindingExpression;
        } 

        void SetDataItem(object newItem)
        {
            _dataItem = CreateReference(newItem); 
        }
 
        // find the DataSource object (if any) that produced the DataContext 
        // for element d
        object GetDataSourceForDataContext(DependencyObject d) 
        {
            // look for ancestor that contributed the inherited value
            DependencyObject ancestor;
            BindingExpression b = null; 

            for (ancestor = d; 
                 ancestor != null; 
                 ancestor = FrameworkElement.GetFrameworkParent(ancestor))
            { 
                if (HasLocalDataContext(ancestor))
                {
                    b = BindingOperations.GetBindingExpression(ancestor, FrameworkElement.DataContextProperty) as BindingExpression;
                    break; 
                }
            } 
 
            if (b != null)
                return b.DataSource; 

            return null;
        }
 
#endregion Helper functions
 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------

        WeakReference           _ctxElement; 
        object                  _dataItem;
        BindingWorker           _worker; 
        IValueConverter         _valueConverter; 
        Type                    _sourceType;
        DataSourceProvider      _dataProvider; 
        object                  _collectionViewSource;
        DynamicValueConverter   _dynamicConverter;

        internal static readonly object NullDataItem = new NamedObject("NullDataItem"); 
        internal static readonly object IgnoreDefaultValue = new NamedObject("IgnoreDefaultValue");
    } 
 
}
 

// 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