CLRBindingWorker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Data / CLRBindingWorker.cs / 1 / CLRBindingWorker.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines ClrBindingWorker object, workhorse for CLR bindings 
// 
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Reflection;
using System.Globalization; 
using System.Windows.Threading;
using System.Threading; 
 
using System.ComponentModel;
 
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls; // Validation
using System.Windows.Data; 
using System.Windows.Markup;     // for GetTypeFromName
using MS.Internal.Controls; // Validation 
using MS.Internal.Utility;              // for GetTypeFromName 
using MS.Utility;
 
namespace MS.Internal.Data
{
    internal class ClrBindingWorker : BindingWorker
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        internal ClrBindingWorker(BindingExpression b, DataBindEngine engine) : base(b)
        {
            PropertyPath path = ParentBinding.Path; 

            if (ParentBinding.XPath != null) 
            { 
                path = PrepareXmlBinding(path);
            } 

            if (path == null)
            {
                path = new PropertyPath(String.Empty); 
            }
 
            if (ParentBinding.Path == null) 
            {
                ParentBinding.UsePath(path); 
            }

            _pathWorker = new PropertyPathWorker(path, this, IsDynamic, engine);
            _pathWorker.SetTreeContext(ParentBindingExpression.TargetElementReference); 
        }
 
        // separate method to avoid loading System.Xml if not needed 
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        PropertyPath PrepareXmlBinding(PropertyPath path) 
        {
            if (path == null)
            {
                DependencyProperty targetDP = TargetProperty; 
                Type targetType = targetDP.PropertyType;
                string pathString; 
 
                if (targetType == typeof(Object))
                { 
                    if (targetDP == System.Windows.Data.BindingExpression.NoTargetProperty ||
                        targetDP == System.Windows.Controls.Primitives.Selector.SelectedValueProperty)
                    {
                        // these properties want the "value" - i.e. the text of 
                        // the first (and usually only) XmlNode
                        pathString = "/InnerText"; 
                    } 
                    else if (targetDP == FrameworkElement.DataContextProperty ||
                              targetDP == CollectionViewSource.SourceProperty) 
                    {
                        // these properties want the entire collection
                        pathString = String.Empty;
                    } 
                    else
                    { 
                        // most object-valued properties want the (current) XmlNode itself 
                        pathString = "/";
                    } 
                }
                else if (targetType.IsAssignableFrom(typeof(XmlDataCollection)))
                {
                    // these properties want the entire collection 
                    pathString = String.Empty;
                } 
                else 
                {
                    // most other properties want the "value" 
                    pathString = "/InnerText";
                }

                path = new PropertyPath(pathString); 
            }
 
            // don't bother to create XmlWorker if we don't even have a valid path 
            if (path.SVI.Length > 0)
            { 
                // tell Xml Worker if desired result is collection, in order to get optimization
                _xmlWorker = new XmlBindingWorker(this, path.SVI[0].drillIn == DrillIn.Never);
            }
            return path; 
        }
 
        //------------------------------------------------------ 
        //
        //  Internal Properties 
        //
        //-----------------------------------------------------

        internal override Type SourcePropertyType 
        {
            get 
            { 
                return PW.GetType(PW.Length - 1);
            } 
        }

        internal override bool IsDBNullValidForUpdate
        { 
            get
            { 
                return PW.IsDBNullValidForUpdate; 
            }
        } 

        internal override object SourceItem
        {
            get 
            {
                return PW.SourceItem; 
            } 
        }
 
        internal override string SourcePropertyName
        {
            get
            { 
                return PW.SourcePropertyName;
            } 
        } 

        //------------------------------------------------------ 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        internal override bool CanUpdate 
        { 
            get
            { 
                PropertyPathWorker ppw = PW;
                int k = PW.Length - 1;

                if (k < 0) 
                    return false;
 
                object item = ppw.GetItem(k); 
                if (item == null || item == BindingExpression.NullDataItem)
                    return false; 

                object accessor = ppw.GetAccessor(k);
                if (accessor == null ||
                    (accessor == DependencyProperty.UnsetValue && XmlWorker == null)) 
                    return false;
 
                return true; 
            }
        } 

        internal override void AttachDataItem()
        {
            object item; 

            if (XmlWorker == null) 
            { 
                item = DataItem;
            } 
            else
            {
                XmlWorker.AttachDataItem();
                item = XmlWorker.RawValue(); 
            }
 
            PW.AttachToRootItem(item); 

            if (PW.Length == 0) 
            {
                ParentBindingExpression.SetupDefaultValueConverter(item.GetType());
            }
        } 

        internal override void DetachDataItem() 
        { 
            PW.DetachFromRootItem();
            if (XmlWorker != null) 
            {
                XmlWorker.DetachDataItem();
            }
 
            // cancel any pending async requests.  If it has already completed,
            // but is now waiting in the dispatcher queue, it will be ignored because 
            // we set _pending*Request to null. 
            if (_pendingGetValueRequest != null)
            { 
                _pendingGetValueRequest.Cancel();
                _pendingGetValueRequest = null;
            }
 
            if (_pendingSetValueRequest != null)
            { 
                _pendingSetValueRequest.Cancel(); 
                _pendingSetValueRequest = null;
            } 
        }

        internal override object RawValue()
        { 
            object rawValue = PW.RawValue();
            SetStatus(PW.Status); 
 
            return rawValue;
        } 

        internal override void RefreshValue()
        {
            PW.RefreshValue(); 
        }
 
        internal override void UpdateValue(object value) 
        {
            int k = PW.Length - 1; 
            object item = PW.GetItem(k);
            if (item == null || item == BindingExpression.NullDataItem)
                return;
 
            // if the binding is async, post a request to set the value
            if (ParentBinding.IsAsync && !(PW.GetAccessor(k) is DependencyProperty)) 
            { 
                RequestAsyncSetValue(item, value);
                return; 
            }

            PW.SetValue(item, value);
        } 

        internal override void OnCurrentChanged(ICollectionView collectionView, EventArgs args) 
        { 
            if (XmlWorker != null)
                XmlWorker.OnCurrentChanged(collectionView, args); 
            PW.OnCurrentChanged(collectionView);
        }

        internal override bool UsesDependencyProperty(DependencyObject d, DependencyProperty dp) 
        {
            return PW.UsesDependencyProperty(d, dp); 
        } 

        internal override void OnSourceInvalidation(DependencyObject d, DependencyProperty dp, bool isASubPropertyChange) 
        {
            PW.OnDependencyPropertyChanged(d, dp, isASubPropertyChange);
        }
 
        internal override ValidationError ValidateDataError(BindingExpressionBase bindingExpressionBase)
        { 
            return PW.ValidateDataError(bindingExpressionBase); 
        }
 
        //-----------------------------------------------------
        //
        //  Internal Properties - callbacks from PropertyPathWorker
        // 
        //------------------------------------------------------
 
        internal bool TransfersDefaultValue 
        {
            get { return ParentBinding.TransfersDefaultValue; } 
        }

        //-----------------------------------------------------
        // 
        //  Internal Methods - callbacks from PropertyPathWorker
        // 
        //----------------------------------------------------- 

        internal void CancelPendingTasks() 
        {
            ParentBindingExpression.CancelPendingTasks();
        }
 
        internal bool AsyncGet(object item, int level)
        { 
            if (ParentBinding.IsAsync) 
            {
                RequestAsyncGetValue(item, level); 
                return true;
            }
            else
                return false; 
        }
 
        internal void ReplaceCurrentItem(ICollectionView oldCollectionView, ICollectionView newCollectionView) 
        {
            // detach from old view 
            if (oldCollectionView != null)
            {
                CurrentChangedEventManager.RemoveListener(oldCollectionView, ParentBindingExpression);
                if (IsReflective) 
                {
                    CurrentChangingEventManager.RemoveListener(oldCollectionView, ParentBindingExpression); 
                } 
            }
 
            // attach to new view
            if (newCollectionView != null)
            {
                CurrentChangedEventManager.AddListener(newCollectionView, ParentBindingExpression); 
                if (IsReflective)
                { 
                    CurrentChangingEventManager.AddListener(newCollectionView, ParentBindingExpression); 
                }
            } 
        }

        internal void NewValueAvailable(bool dependencySourcesChanged, bool initialValue, bool isASubPropertyChange)
        { 
            SetStatus(PW.Status);
 
            if (dependencySourcesChanged) 
            {
                ReplaceDependencySources(); 
            }

            // if there's a revised value (i.e. not during initialization
            // and shutdown), transfer it. 
            if (!initialValue && Status != BindingStatus.AsyncRequestPending)
            { 
                ParentBindingExpression.ScheduleTransfer(isASubPropertyChange); 
            }
        } 

        internal void SetupDefaultValueConverter(Type type)
        {
            ParentBindingExpression.SetupDefaultValueConverter(type); 
        }
 
        internal bool IsValidValue(object value) 
        {
            return TargetProperty.IsValidValue(value); 
        }

        internal void OnSourcePropertyChanged(object o, string propName)
        { 
            int level;
 
            // ignore changes that don't affect this binding. 
            // This test must come before any marshalling to the right context (bug 892484)
            if (!IgnoreSourcePropertyChange && (level = PW.LevelForPropertyChange(o, propName)) >= 0) 
            {
                // if notification was on the right thread, just do the work (normal case)
                if (Dispatcher.Thread == Thread.CurrentThread)
                { 
                    PW.OnPropertyChangedAtLevel(level);
                } 
                else 
                {
                    // otherwise invoke an operation to do the work on the right context 
                    SetTransferIsPending(true);
                    Dispatcher.BeginInvoke(
                        DispatcherPriority.DataBind,
                        new DispatcherOperationCallback(ScheduleTransferOperation), 
                        new object[]{o, propName});
                } 
            } 
        }
 
        // called by the child XmlBindingWorker when an xml change is detected
        // but the identity of raw value has not changed.
        internal void OnXmlValueChanged()
        { 
            // treat this as a property change at the top level
            object item = PW.GetItem(0); 
            OnSourcePropertyChanged(item, null); 
        }
 
        // called by the child XmlBindingWorker when there's a new raw value
        internal void UseNewXmlItem(object item)
        {
            PW.DetachFromRootItem(); 
            PW.AttachToRootItem(item);
            if (Status != BindingStatus.AsyncRequestPending) 
            { 
                ParentBindingExpression.ScheduleTransfer(false);
            } 
        }

        // called by the child XmlBindingWorker to get the current "result node"
        internal object GetResultNode() 
        {
            return PW.GetItem(0); 
        } 

        internal DependencyObject CheckTarget() 
        {
            // if the target has been GC'd, this will shut down the binding
            return TargetElement;
        } 

        internal void ReportGetValueError(int k, object item, Exception ex) 
        { 
            if (TraceData.IsEnabled)
            { 
                SourceValueInfo svi = PW.GetSourceValueInfo(k);
                Type type = PW.GetType(k);
                string parentName = (k>0)? PW.GetSourceValueInfo(k-1).name : String.Empty;
                TraceData.Trace(ParentBindingExpression.TraceLevel, 
                        TraceData.CannotGetClrRawValue(
                            svi.propertyName, type.Name, 
                            parentName, AvTrace.TypeName(item)), 
                        ParentBindingExpression, ex);
            } 
        }

        internal void ReportSetValueError(int k, object item, object value, Exception ex)
        { 
            if (TraceData.IsEnabled)
            { 
                SourceValueInfo svi = PW.GetSourceValueInfo(k); 
                Type type = PW.GetType(k);
                TraceData.Trace(TraceEventType.Error, 
                        TraceData.CannotSetClrRawValue(
                            svi.propertyName, type.Name,
                            AvTrace.TypeName(item),
                            AvTrace.ToStringHelper(value), 
                            AvTrace.TypeName(value)),
                        ParentBindingExpression, ex); 
            } 
        }
 
        internal void ReportRawValueErrors(int k, object item, object info)
        {
            if (TraceData.IsEnabled)
            { 
                if (item == null)
                { 
                    // There is probably no data item; e.g. we've moved currency off of a list. 
                    // the type of the missing item is supposed to be _arySVS[k].info.DeclaringType
                    // the property we're looking for is named _arySVS[k].name 
                    TraceData.Trace(TraceEventType.Information, TraceData.MissingDataItem, ParentBindingExpression);
                }

                if (info == null) 
                {
                    // this no info problem should have been error reported at ReplaceItem already. 
 
                    // this can happen when parent is Nullable with no value
                    // check _arySVS[k-1].info.ComponentType 
                    //if (!IsNullableType(_arySVS[k-1].info.ComponentType))
                    TraceData.Trace(TraceEventType.Information, TraceData.MissingInfo, ParentBindingExpression);
                }
 
                if (item == BindingExpression.NullDataItem)
                { 
                    // this is OK, not an error. 
                    // this can happen when detaching bindings.
                    // this can happen when binding has a Nullable data item with no value 
                    TraceData.Trace(TraceEventType.Information, TraceData.NullDataItem, ParentBindingExpression);
                }
            }
        } 

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

        PropertyPathWorker PW { get { return _pathWorker; } }
        XmlBindingWorker XmlWorker { get { return _xmlWorker; } } 

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

        void SetStatus(PropertyPathStatus status)
        { 
            switch (status)
            { 
                case PropertyPathStatus.Inactive: 
                    Status = BindingStatus.Inactive;
                    break; 
                case PropertyPathStatus.Active:
                    Status = BindingStatus.Active;
                    break;
                case PropertyPathStatus.PathError: 
                    Status = BindingStatus.PathError;
                    break; 
                case PropertyPathStatus.AsyncRequestPending: 
                    Status = BindingStatus.AsyncRequestPending;
                    break; 
            }
        }

        void ReplaceDependencySources() 
        {
            if (!ParentBindingExpression.IsDetaching) 
            { 
                WeakDependencySource[] newSources = new WeakDependencySource[PW.Length];
                int n = 0; 

                if (IsDynamic)
                {
                    for (int k=0; k= 0)
            { 
                PW.OnPropertyChangedAtLevel(level); 
            }
 
            return null;
        }

#endregion Callbacks 

        //------------------------------------------------------ 
        // 
        //  Private Enums, Structs, Constants
        // 
        //-----------------------------------------------------

        static readonly AsyncRequestCallback DoGetValueCallback = new AsyncRequestCallback(OnGetValueCallback);
        static readonly AsyncRequestCallback CompleteGetValueCallback = new AsyncRequestCallback(OnCompleteGetValueCallback); 
        static readonly DispatcherOperationCallback CompleteGetValueLocalCallback = new DispatcherOperationCallback(OnCompleteGetValueOperation);
        static readonly AsyncRequestCallback DoSetValueCallback = new AsyncRequestCallback(OnSetValueCallback); 
        static readonly AsyncRequestCallback CompleteSetValueCallback = new AsyncRequestCallback(OnCompleteSetValueCallback); 
        static readonly DispatcherOperationCallback CompleteSetValueLocalCallback = new DispatcherOperationCallback(OnCompleteSetValueOperation);
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        PropertyPathWorker  _pathWorker; 
        XmlBindingWorker    _xmlWorker;
 
        AsyncGetValueRequest _pendingGetValueRequest;
        AsyncSetValueRequest _pendingSetValueRequest;

        Type[]              _types = new Type[1]; 
        object[]            _values = new object[1];
    } 
 
    internal class WeakDependencySource
    { 
        internal WeakDependencySource(DependencyObject item, DependencyProperty dp)
        {
            _item = BindingExpressionBase.CreateReference(item);
            _dp = dp; 
        }
 
        internal WeakDependencySource(WeakReference wr, DependencyProperty dp) 
        {
            _item = wr; 
            _dp = dp;
        }

        internal DependencyObject DependencyObject { get { return (DependencyObject)BindingExpressionBase.GetReference(_item); } } 
        internal DependencyProperty DependencyProperty { get { return _dp; } }
 
        object _item; 
        DependencyProperty _dp;
    } 
}

// 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 ClrBindingWorker object, workhorse for CLR bindings 
// 
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Reflection;
using System.Globalization; 
using System.Windows.Threading;
using System.Threading; 
 
using System.ComponentModel;
 
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls; // Validation
using System.Windows.Data; 
using System.Windows.Markup;     // for GetTypeFromName
using MS.Internal.Controls; // Validation 
using MS.Internal.Utility;              // for GetTypeFromName 
using MS.Utility;
 
namespace MS.Internal.Data
{
    internal class ClrBindingWorker : BindingWorker
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        internal ClrBindingWorker(BindingExpression b, DataBindEngine engine) : base(b)
        {
            PropertyPath path = ParentBinding.Path; 

            if (ParentBinding.XPath != null) 
            { 
                path = PrepareXmlBinding(path);
            } 

            if (path == null)
            {
                path = new PropertyPath(String.Empty); 
            }
 
            if (ParentBinding.Path == null) 
            {
                ParentBinding.UsePath(path); 
            }

            _pathWorker = new PropertyPathWorker(path, this, IsDynamic, engine);
            _pathWorker.SetTreeContext(ParentBindingExpression.TargetElementReference); 
        }
 
        // separate method to avoid loading System.Xml if not needed 
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        PropertyPath PrepareXmlBinding(PropertyPath path) 
        {
            if (path == null)
            {
                DependencyProperty targetDP = TargetProperty; 
                Type targetType = targetDP.PropertyType;
                string pathString; 
 
                if (targetType == typeof(Object))
                { 
                    if (targetDP == System.Windows.Data.BindingExpression.NoTargetProperty ||
                        targetDP == System.Windows.Controls.Primitives.Selector.SelectedValueProperty)
                    {
                        // these properties want the "value" - i.e. the text of 
                        // the first (and usually only) XmlNode
                        pathString = "/InnerText"; 
                    } 
                    else if (targetDP == FrameworkElement.DataContextProperty ||
                              targetDP == CollectionViewSource.SourceProperty) 
                    {
                        // these properties want the entire collection
                        pathString = String.Empty;
                    } 
                    else
                    { 
                        // most object-valued properties want the (current) XmlNode itself 
                        pathString = "/";
                    } 
                }
                else if (targetType.IsAssignableFrom(typeof(XmlDataCollection)))
                {
                    // these properties want the entire collection 
                    pathString = String.Empty;
                } 
                else 
                {
                    // most other properties want the "value" 
                    pathString = "/InnerText";
                }

                path = new PropertyPath(pathString); 
            }
 
            // don't bother to create XmlWorker if we don't even have a valid path 
            if (path.SVI.Length > 0)
            { 
                // tell Xml Worker if desired result is collection, in order to get optimization
                _xmlWorker = new XmlBindingWorker(this, path.SVI[0].drillIn == DrillIn.Never);
            }
            return path; 
        }
 
        //------------------------------------------------------ 
        //
        //  Internal Properties 
        //
        //-----------------------------------------------------

        internal override Type SourcePropertyType 
        {
            get 
            { 
                return PW.GetType(PW.Length - 1);
            } 
        }

        internal override bool IsDBNullValidForUpdate
        { 
            get
            { 
                return PW.IsDBNullValidForUpdate; 
            }
        } 

        internal override object SourceItem
        {
            get 
            {
                return PW.SourceItem; 
            } 
        }
 
        internal override string SourcePropertyName
        {
            get
            { 
                return PW.SourcePropertyName;
            } 
        } 

        //------------------------------------------------------ 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        internal override bool CanUpdate 
        { 
            get
            { 
                PropertyPathWorker ppw = PW;
                int k = PW.Length - 1;

                if (k < 0) 
                    return false;
 
                object item = ppw.GetItem(k); 
                if (item == null || item == BindingExpression.NullDataItem)
                    return false; 

                object accessor = ppw.GetAccessor(k);
                if (accessor == null ||
                    (accessor == DependencyProperty.UnsetValue && XmlWorker == null)) 
                    return false;
 
                return true; 
            }
        } 

        internal override void AttachDataItem()
        {
            object item; 

            if (XmlWorker == null) 
            { 
                item = DataItem;
            } 
            else
            {
                XmlWorker.AttachDataItem();
                item = XmlWorker.RawValue(); 
            }
 
            PW.AttachToRootItem(item); 

            if (PW.Length == 0) 
            {
                ParentBindingExpression.SetupDefaultValueConverter(item.GetType());
            }
        } 

        internal override void DetachDataItem() 
        { 
            PW.DetachFromRootItem();
            if (XmlWorker != null) 
            {
                XmlWorker.DetachDataItem();
            }
 
            // cancel any pending async requests.  If it has already completed,
            // but is now waiting in the dispatcher queue, it will be ignored because 
            // we set _pending*Request to null. 
            if (_pendingGetValueRequest != null)
            { 
                _pendingGetValueRequest.Cancel();
                _pendingGetValueRequest = null;
            }
 
            if (_pendingSetValueRequest != null)
            { 
                _pendingSetValueRequest.Cancel(); 
                _pendingSetValueRequest = null;
            } 
        }

        internal override object RawValue()
        { 
            object rawValue = PW.RawValue();
            SetStatus(PW.Status); 
 
            return rawValue;
        } 

        internal override void RefreshValue()
        {
            PW.RefreshValue(); 
        }
 
        internal override void UpdateValue(object value) 
        {
            int k = PW.Length - 1; 
            object item = PW.GetItem(k);
            if (item == null || item == BindingExpression.NullDataItem)
                return;
 
            // if the binding is async, post a request to set the value
            if (ParentBinding.IsAsync && !(PW.GetAccessor(k) is DependencyProperty)) 
            { 
                RequestAsyncSetValue(item, value);
                return; 
            }

            PW.SetValue(item, value);
        } 

        internal override void OnCurrentChanged(ICollectionView collectionView, EventArgs args) 
        { 
            if (XmlWorker != null)
                XmlWorker.OnCurrentChanged(collectionView, args); 
            PW.OnCurrentChanged(collectionView);
        }

        internal override bool UsesDependencyProperty(DependencyObject d, DependencyProperty dp) 
        {
            return PW.UsesDependencyProperty(d, dp); 
        } 

        internal override void OnSourceInvalidation(DependencyObject d, DependencyProperty dp, bool isASubPropertyChange) 
        {
            PW.OnDependencyPropertyChanged(d, dp, isASubPropertyChange);
        }
 
        internal override ValidationError ValidateDataError(BindingExpressionBase bindingExpressionBase)
        { 
            return PW.ValidateDataError(bindingExpressionBase); 
        }
 
        //-----------------------------------------------------
        //
        //  Internal Properties - callbacks from PropertyPathWorker
        // 
        //------------------------------------------------------
 
        internal bool TransfersDefaultValue 
        {
            get { return ParentBinding.TransfersDefaultValue; } 
        }

        //-----------------------------------------------------
        // 
        //  Internal Methods - callbacks from PropertyPathWorker
        // 
        //----------------------------------------------------- 

        internal void CancelPendingTasks() 
        {
            ParentBindingExpression.CancelPendingTasks();
        }
 
        internal bool AsyncGet(object item, int level)
        { 
            if (ParentBinding.IsAsync) 
            {
                RequestAsyncGetValue(item, level); 
                return true;
            }
            else
                return false; 
        }
 
        internal void ReplaceCurrentItem(ICollectionView oldCollectionView, ICollectionView newCollectionView) 
        {
            // detach from old view 
            if (oldCollectionView != null)
            {
                CurrentChangedEventManager.RemoveListener(oldCollectionView, ParentBindingExpression);
                if (IsReflective) 
                {
                    CurrentChangingEventManager.RemoveListener(oldCollectionView, ParentBindingExpression); 
                } 
            }
 
            // attach to new view
            if (newCollectionView != null)
            {
                CurrentChangedEventManager.AddListener(newCollectionView, ParentBindingExpression); 
                if (IsReflective)
                { 
                    CurrentChangingEventManager.AddListener(newCollectionView, ParentBindingExpression); 
                }
            } 
        }

        internal void NewValueAvailable(bool dependencySourcesChanged, bool initialValue, bool isASubPropertyChange)
        { 
            SetStatus(PW.Status);
 
            if (dependencySourcesChanged) 
            {
                ReplaceDependencySources(); 
            }

            // if there's a revised value (i.e. not during initialization
            // and shutdown), transfer it. 
            if (!initialValue && Status != BindingStatus.AsyncRequestPending)
            { 
                ParentBindingExpression.ScheduleTransfer(isASubPropertyChange); 
            }
        } 

        internal void SetupDefaultValueConverter(Type type)
        {
            ParentBindingExpression.SetupDefaultValueConverter(type); 
        }
 
        internal bool IsValidValue(object value) 
        {
            return TargetProperty.IsValidValue(value); 
        }

        internal void OnSourcePropertyChanged(object o, string propName)
        { 
            int level;
 
            // ignore changes that don't affect this binding. 
            // This test must come before any marshalling to the right context (bug 892484)
            if (!IgnoreSourcePropertyChange && (level = PW.LevelForPropertyChange(o, propName)) >= 0) 
            {
                // if notification was on the right thread, just do the work (normal case)
                if (Dispatcher.Thread == Thread.CurrentThread)
                { 
                    PW.OnPropertyChangedAtLevel(level);
                } 
                else 
                {
                    // otherwise invoke an operation to do the work on the right context 
                    SetTransferIsPending(true);
                    Dispatcher.BeginInvoke(
                        DispatcherPriority.DataBind,
                        new DispatcherOperationCallback(ScheduleTransferOperation), 
                        new object[]{o, propName});
                } 
            } 
        }
 
        // called by the child XmlBindingWorker when an xml change is detected
        // but the identity of raw value has not changed.
        internal void OnXmlValueChanged()
        { 
            // treat this as a property change at the top level
            object item = PW.GetItem(0); 
            OnSourcePropertyChanged(item, null); 
        }
 
        // called by the child XmlBindingWorker when there's a new raw value
        internal void UseNewXmlItem(object item)
        {
            PW.DetachFromRootItem(); 
            PW.AttachToRootItem(item);
            if (Status != BindingStatus.AsyncRequestPending) 
            { 
                ParentBindingExpression.ScheduleTransfer(false);
            } 
        }

        // called by the child XmlBindingWorker to get the current "result node"
        internal object GetResultNode() 
        {
            return PW.GetItem(0); 
        } 

        internal DependencyObject CheckTarget() 
        {
            // if the target has been GC'd, this will shut down the binding
            return TargetElement;
        } 

        internal void ReportGetValueError(int k, object item, Exception ex) 
        { 
            if (TraceData.IsEnabled)
            { 
                SourceValueInfo svi = PW.GetSourceValueInfo(k);
                Type type = PW.GetType(k);
                string parentName = (k>0)? PW.GetSourceValueInfo(k-1).name : String.Empty;
                TraceData.Trace(ParentBindingExpression.TraceLevel, 
                        TraceData.CannotGetClrRawValue(
                            svi.propertyName, type.Name, 
                            parentName, AvTrace.TypeName(item)), 
                        ParentBindingExpression, ex);
            } 
        }

        internal void ReportSetValueError(int k, object item, object value, Exception ex)
        { 
            if (TraceData.IsEnabled)
            { 
                SourceValueInfo svi = PW.GetSourceValueInfo(k); 
                Type type = PW.GetType(k);
                TraceData.Trace(TraceEventType.Error, 
                        TraceData.CannotSetClrRawValue(
                            svi.propertyName, type.Name,
                            AvTrace.TypeName(item),
                            AvTrace.ToStringHelper(value), 
                            AvTrace.TypeName(value)),
                        ParentBindingExpression, ex); 
            } 
        }
 
        internal void ReportRawValueErrors(int k, object item, object info)
        {
            if (TraceData.IsEnabled)
            { 
                if (item == null)
                { 
                    // There is probably no data item; e.g. we've moved currency off of a list. 
                    // the type of the missing item is supposed to be _arySVS[k].info.DeclaringType
                    // the property we're looking for is named _arySVS[k].name 
                    TraceData.Trace(TraceEventType.Information, TraceData.MissingDataItem, ParentBindingExpression);
                }

                if (info == null) 
                {
                    // this no info problem should have been error reported at ReplaceItem already. 
 
                    // this can happen when parent is Nullable with no value
                    // check _arySVS[k-1].info.ComponentType 
                    //if (!IsNullableType(_arySVS[k-1].info.ComponentType))
                    TraceData.Trace(TraceEventType.Information, TraceData.MissingInfo, ParentBindingExpression);
                }
 
                if (item == BindingExpression.NullDataItem)
                { 
                    // this is OK, not an error. 
                    // this can happen when detaching bindings.
                    // this can happen when binding has a Nullable data item with no value 
                    TraceData.Trace(TraceEventType.Information, TraceData.NullDataItem, ParentBindingExpression);
                }
            }
        } 

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

        PropertyPathWorker PW { get { return _pathWorker; } }
        XmlBindingWorker XmlWorker { get { return _xmlWorker; } } 

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

        void SetStatus(PropertyPathStatus status)
        { 
            switch (status)
            { 
                case PropertyPathStatus.Inactive: 
                    Status = BindingStatus.Inactive;
                    break; 
                case PropertyPathStatus.Active:
                    Status = BindingStatus.Active;
                    break;
                case PropertyPathStatus.PathError: 
                    Status = BindingStatus.PathError;
                    break; 
                case PropertyPathStatus.AsyncRequestPending: 
                    Status = BindingStatus.AsyncRequestPending;
                    break; 
            }
        }

        void ReplaceDependencySources() 
        {
            if (!ParentBindingExpression.IsDetaching) 
            { 
                WeakDependencySource[] newSources = new WeakDependencySource[PW.Length];
                int n = 0; 

                if (IsDynamic)
                {
                    for (int k=0; k= 0)
            { 
                PW.OnPropertyChangedAtLevel(level); 
            }
 
            return null;
        }

#endregion Callbacks 

        //------------------------------------------------------ 
        // 
        //  Private Enums, Structs, Constants
        // 
        //-----------------------------------------------------

        static readonly AsyncRequestCallback DoGetValueCallback = new AsyncRequestCallback(OnGetValueCallback);
        static readonly AsyncRequestCallback CompleteGetValueCallback = new AsyncRequestCallback(OnCompleteGetValueCallback); 
        static readonly DispatcherOperationCallback CompleteGetValueLocalCallback = new DispatcherOperationCallback(OnCompleteGetValueOperation);
        static readonly AsyncRequestCallback DoSetValueCallback = new AsyncRequestCallback(OnSetValueCallback); 
        static readonly AsyncRequestCallback CompleteSetValueCallback = new AsyncRequestCallback(OnCompleteSetValueCallback); 
        static readonly DispatcherOperationCallback CompleteSetValueLocalCallback = new DispatcherOperationCallback(OnCompleteSetValueOperation);
 
        //------------------------------------------------------
        //
        //  Private Fields
        // 
        //-----------------------------------------------------
 
        PropertyPathWorker  _pathWorker; 
        XmlBindingWorker    _xmlWorker;
 
        AsyncGetValueRequest _pendingGetValueRequest;
        AsyncSetValueRequest _pendingSetValueRequest;

        Type[]              _types = new Type[1]; 
        object[]            _values = new object[1];
    } 
 
    internal class WeakDependencySource
    { 
        internal WeakDependencySource(DependencyObject item, DependencyProperty dp)
        {
            _item = BindingExpressionBase.CreateReference(item);
            _dp = dp; 
        }
 
        internal WeakDependencySource(WeakReference wr, DependencyProperty dp) 
        {
            _item = wr; 
            _dp = dp;
        }

        internal DependencyObject DependencyObject { get { return (DependencyObject)BindingExpressionBase.GetReference(_item); } } 
        internal DependencyProperty DependencyProperty { get { return _dp; } }
 
        object _item; 
        DependencyProperty _dp;
    } 
}

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