CLRBindingWorker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Data / CLRBindingWorker.cs / 1305600 / 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 override bool IsPathCurrent()
        {
            object item = (XmlWorker == null) ? DataItem : XmlWorker.RawValue();
            return PW.IsPathCurrent(item); 
        }
 
        //----------------------------------------------------- 
        //
        //  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);

            BindingExpression parent = ParentBindingExpression; 

            // this method is called when the last item in the path is replaced. 
            // BindingGroup also wants to know about this. 
            BindingGroup bindingGroup = parent.BindingGroup;
            if (bindingGroup != null) 
            {
                bindingGroup.UpdateTable(parent);
            }
 
            if (dependencySourcesChanged)
            { 
                ReplaceDependencySources(); 
            }
 
            // if there's a revised value (i.e. not during initialization
            // and shutdown), transfer it.
            if (!initialValue && Status != BindingStatus.AsyncRequestPending)
            { 
                parent.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);
                } 
            }
        }

        internal void ReportBadXPath(TraceEventType traceType) 
        {
            if (_xmlWorker != null) 
            { 
                _xmlWorker.ReportBadXPath(traceType);
            } 
        }

        //-----------------------------------------------------
        // 
        //  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)
            { 
                int size = PW.Length;
                if (PW.NeedsDirectNotification) 
                    ++size; 

                WeakDependencySource[] newSources = new WeakDependencySource[size]; 
                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