PriorityBindingExpression.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 / PriorityBindingExpression.cs / 2 / PriorityBindingExpression.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines PriorityBindingExpression object, which chooses a BindingExpression out 
//              of a list of BindingExpressions in order of "priority" (and falls back 
//              to the next BindingExpression as each BindingExpression fails)
// 
// See spec at [....]/connecteddata/Specs/Data%20Binding.mht
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections; 
using System.Collections.ObjectModel;   // Collection 
using System.Diagnostics;
using System.Threading; 
using System.Windows.Threading;
using System.Windows.Markup;
using MS.Internal;
using MS.Internal.Data; 
using MS.Utility;
 
namespace System.Windows.Data 
{
 
/// 
///  Describes a collection of BindingExpressions attached to a single property.
///     These behave as "priority" BindingExpressions, meaning that the property
///     receives its value from the first BindingExpression in the collection that 
///     can produce a legal value.
///  
public sealed class PriorityBindingExpression : BindingExpressionBase 
{
 
    //-----------------------------------------------------
    //
    //  Constructors
    // 
    //-----------------------------------------------------
 
    private PriorityBindingExpression(PriorityBinding binding, BindingExpressionBase owner) 
        : base(binding, owner)
    { 
    }

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

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

    ///  List of inner BindingExpression 
    public ReadOnlyCollection   BindingExpressions 
    {
        get { return new ReadOnlyCollection(MutableBindingExpressions); } 
    } 

    ///  Returns the active BindingExpression (or null)  
    public BindingExpressionBase ActiveBindingExpression
    {
        get { return (_activeIndex < 0) ? null : MutableBindingExpressions[_activeIndex]; }
    } 

    //------------------------------------------------------ 
    // 
    //  Public Methods
    // 
    //------------------------------------------------------

#region Expression overrides
 
    /// 
    ///     Called to evaluate the Expression value 
    ///  
    /// DependencyObject being queried
    /// Property being queried 
    /// Computed value. Unset 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)
    { 
        BindingExpressionBase bindExpr = ActiveBindingExpression; 
        if (bindExpr != null)
            return bindExpr.SetValue(d, dp, value); 

        // If we couldn't find the active binding, just return true to keep the property
        // engine from removing the PriorityBinding.
        return true; 
    }
 
    ///  
    ///     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 this method is changed to use d or dp directly, uncomment these lines 
        //if (d == null) 
        //    throw new ArgumentNullException(d);
        //if (dp == null) 
        //    throw new ArgumentNullException(dp);

        // 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.
        { 
            Dispatcher.BeginInvoke(
                DispatcherPriority.DataBind,
                new DispatcherOperationCallback(HandlePropertyInvalidationOperation),
                new object[]{d, args}); 
        }
    } 
 
#endregion  Expression overrides
 
    //-----------------------------------------------------
    //
    //  Internal Methods
    // 
    //------------------------------------------------------
 
    // Create a new BindingExpression from the given Binding description 
    internal static PriorityBindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, PriorityBinding binding, BindingExpressionBase owner)
    { 
        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 
        PriorityBindingExpression bindExpr = new PriorityBindingExpression(binding, owner); 

        return bindExpr; 
    }

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

    ///  
    ///     Number of BindingExpressions that have been attached and are listening
    /// 
    internal int AttentiveBindingExpressions
    { 
        get { return (_activeIndex == NoActiveBindingExpressions) ? MutableBindingExpressions.Count : _activeIndex + 1; }
    } 
 
    //-----------------------------------------------------
    // 
    //  Protected Internal Methods
    //
    //------------------------------------------------------
 
    /// 
    ///     Attach a BindingExpression to the given target (element, property) 
    ///  
    /// DependencyObject being set
    /// Property being set 
    internal override void AttachOverride(DependencyObject d, DependencyProperty dp)
    {
        base.AttachOverride(d, dp);
 
        DependencyObject target = TargetElement;
        if (target == null) 
            return; 

        SetStatus(BindingStatus.Active); 

        int count = ParentPriorityBinding.Bindings.Count;
        _activeIndex = NoActiveBindingExpressions;
        Debug.Assert(MutableBindingExpressions.Count == 0, "expect to encounter empty BindingExpression collection when attaching MultiBinding"); 
        for (int i = 0; i < count; ++i)
        { 
            AttachBindingExpression(i, false);   // create new binding and have it added to end 
        }
    } 

    ///  sever all connections 
    internal override void DetachOverride()
    { 
        // Theoretically, we only need to detach number of AttentiveBindings,
        // but we'll traverse the whole list anyway and do aggressive clean-up. 
        int count = MutableBindingExpressions.Count; 
        for (int i = 0; i < count; ++i)
        { 
            BindingExpressionBase b = MutableBindingExpressions[i];
            if (b != null)
                b.Detach();
        } 

        ChangeSources(null); 
 
        base.DetachOverride();
    } 

    /// 
    /// Invalidate the given child expression.
    ///  
    internal override void InvalidateChild(BindingExpressionBase bindingExpression)
    { 
        // Prevent re-entrancy, because ChooseActiveBindingExpression() may 
        // activate/deactivate a BindingExpression that indirectly calls this again.
        if (_isInInvalidateBinding) 
            return;
        _isInInvalidateBinding = true;

        int index = MutableBindingExpressions.IndexOf(bindingExpression); 
        DependencyObject target = TargetElement;
 
        if (target != null && 0 <= index && index < AttentiveBindingExpressions) 
        {
            // Optimization: only look for new ActiveBindingExpression when necessary: 
            // 1. it is a higher priority BindingExpression (or there's no ActiveBindingExpression), or
            // 2. the existing ActiveBindingExpression is broken
            if (    index != _activeIndex
                ||  (bindingExpression.Status != BindingStatus.Active && !bindingExpression.UsingFallbackValue)) 
            {
                ChooseActiveBindingExpression(target); 
            } 

            // update the value 
            UsingFallbackValue = false;
            BindingExpressionBase bindExpr = ActiveBindingExpression;
            object newValue = (bindExpr != null) ? bindExpr.GetValue(target, TargetProperty) : UseFallbackValue();
            ChangeValue(newValue, true); 

            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Transfer)) 
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.PriorityTransfer( 
                                        TraceData.Identify(this),
                                        TraceData.Identify(newValue),
                                        _activeIndex,
                                        TraceData.Identify(bindExpr))); 
            }
 
            // 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)
            {
                // recompute expression
                target.InvalidateProperty(TargetProperty); 
            }
        } 
 
        _isInInvalidateBinding = false;
    } 

    /// 
    /// Change the dependency sources for the given child expression.
    ///  
    internal override void ChangeSourcesForChild(BindingExpressionBase bindingExpression, WeakDependencySource[] newSources)
    { 
        int index = MutableBindingExpressions.IndexOf(bindingExpression); 
        DependencyObject target = TargetElement;
 
        if (target != null && index >= 0)
        {
            WeakDependencySource[] combinedSources = CombineSources(index, MutableBindingExpressions, AttentiveBindingExpressions, newSources);
            ChangeSources(combinedSources); 
        }
    } 
 
    /// 
    /// Replace the given child expression with a new one. 
    /// 
    internal override void ReplaceChild(BindingExpressionBase bindingExpression)
    {
        int index = MutableBindingExpressions.IndexOf(bindingExpression); 
        DependencyObject target = TargetElement;
 
        if (index >= 0 && target != null) 
        {
            // clean up the old BindingExpression 
            bindingExpression.Detach();

            // create a replacement BindingExpression and put it in the collection
            bindingExpression = AttachBindingExpression(index, true); 
        }
    } 
 
    //-----------------------------------------------------
    // 
    //  Private Properties
    //
    //------------------------------------------------------
 
    /// 
    /// expose a mutable version of the list of all BindingExpressions; 
    /// derived internal classes need to be able to populate this list 
    /// 
    private Collection MutableBindingExpressions 
    {
        get { return _list; }
    }
 
    //------------------------------------------------------
    // 
    //  Private Methods 
    //
    //----------------------------------------------------- 


    // Create a BindingExpression for position i
    BindingExpressionBase AttachBindingExpression(int i, bool replaceExisting) 
    {
        DependencyObject target = TargetElement; 
        if (target == null) 
            return null;
 
        BindingBase binding = ParentPriorityBinding.Bindings[i];

        BindingExpressionBase bindExpr = binding.CreateBindingExpression(target, TargetProperty, this);
        if (replaceExisting) // replace exisiting or add as new binding? 
            MutableBindingExpressions[i] = bindExpr;
        else 
            MutableBindingExpressions.Add(bindExpr); 

        bindExpr.Attach(target, TargetProperty); 
        return bindExpr;
    }

    // Re-evaluate the choice of active BindingExpression 
    void ChooseActiveBindingExpression(DependencyObject target)
    { 
        int i, count = MutableBindingExpressions.Count; 
        for (i = 0; i < count; ++i)
        { 
            BindingExpressionBase bindExpr = MutableBindingExpressions[i];

            // Try to activate the BindingExpression if it isn't already activate
            if (bindExpr.Status == BindingStatus.Inactive) 
                bindExpr.Activate();
 
            if (bindExpr.Status == BindingStatus.Active || bindExpr.UsingFallbackValue) 
                break;
        } 

        int newActiveIndex = (i < count) ? i : NoActiveBindingExpressions;

        // if active changes, tell the property engine the new list of sources 
        if (newActiveIndex != _activeIndex)
        { 
            int oldActiveIndex = _activeIndex; 

            // get new list of sources 
            _activeIndex = newActiveIndex;
            WeakDependencySource[] newSources = CombineSources(-1, MutableBindingExpressions, AttentiveBindingExpressions, null);

            // tell property engine 
            ChangeSources(newSources);
 
            // deactivate BindingExpressions that don't need to be attentive 
            //
            if (newActiveIndex != NoActiveBindingExpressions) 
                for (i = oldActiveIndex; i > newActiveIndex; --i)
                    MutableBindingExpressions[i].Deactivate();
        }
    } 

    private void ChangeValue() 
    { 
    }
 
    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; 
        int n = AttentiveBindingExpressions; 

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

        for (int i=0; i  _list = new Collection();
    int         _activeIndex            = UnknownActiveBindingExpression;
    bool        _isInInvalidateBinding  = false; 
}
 
} 

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