MultiBindingExpression.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 / MultiBindingExpression.cs / 3 / MultiBindingExpression.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Defines MultiBindingExpression object, uses a collection of BindingExpressions together. 
// 
// 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.Globalization;
using System.Windows.Threading; 
using System.Threading;
using System.Windows.Controls;
using System.Windows.Input;         // FocusChangedEvent
using System.Windows.Markup; 
using MS.Internal.Controls; // Validation
using MS.Internal.KnownBoxes; 
using MS.Internal.Data; 
using MS.Utility;
using MS.Internal;                  // Invariant.Assert 

namespace System.Windows.Data
{
 
/// 
///  Describes a collection of BindingExpressions attached to a single property. 
///     The inner BindingExpressions contribute their values to the MultiBindingExpression, 
///     which combines/converts them into a resultant final value.
///     In the reverse direction, the target value is tranlated to 
///     a set of values that are fed back into the inner BindingExpressions.
/// 
public sealed class MultiBindingExpression: BindingExpressionBase, IDataBindEngineClient
{ 

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

    ///  Constructor 
    private MultiBindingExpression(MultiBinding binding, BindingExpressionBase owner) 
        : base(binding, owner)
    { 
        int count = binding.Bindings.Count; 

        // reduce repeated allocations 
        _tempValues = new object[count];
        _tempTypes = new Type[count];
    }
 
    //------------------------------------------------------
    // 
    //  Interfaces 
    //
    //----------------------------------------------------- 

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

    bool IDataBindEngineClient.AttachToContext(bool lastChance)
    { 
        AttachToContext(lastChance);
        return !TransferIsDeferred; 
    } 

    void IDataBindEngineClient.OnTargetUpdated() 
    {
        OnTargetUpdated();
    }
 
    DependencyObject IDataBindEngineClient.TargetElement
    { 
        get { return TargetElement; } 
    }
 
    //------------------------------------------------------
    //
    //  Public Properties
    // 
    //------------------------------------------------------
 
    ///  Binding from which this expression was created  
    public MultiBinding ParentMultiBinding { get { return (MultiBinding)ParentBindingBase; } }
 
    ///  List of inner BindingExpression 
    public ReadOnlyCollection   BindingExpressions
    {
        get { return new ReadOnlyCollection(MutableBindingExpressions); } 
    }
 
    //----------------------------------------------------- 
    //
    //  Public Methods 
    //
    //------------------------------------------------------

    ///  Send the current value back to the source(s)  
    ///  Does nothing when binding's Mode is not TwoWay or OneWayToSource 
    public override void UpdateSource() 
    { 
        // ultimately, what would be better would be to have a status flag that
        // indicates that this MultiBindingExpression has been Detached, as opposed to a 
        // MultiBindingExpression that doesn't have anything in its BindingExpressions collection
        // in the first place.  Added to which, there should be distinct error
        // messages for both of these error conditions.
        if (MutableBindingExpressions.Count == 0) 
            throw new InvalidOperationException(SR.Get(SRID.BindingExpressionIsDetached));
 
        NeedsUpdate = true;     // force update 
        Update(true);           // update synchronously
    } 

    ///  Force a data transfer from sources to target 
    ///  Will transfer data even if binding's Mode is OneWay 
    public override void UpdateTarget() 
    {
        // ultimately, what would be better would be to have a status flag that 
        // indicates that this MultiBindingExpression has been Detached, as opposed to a 
        // MultiBindingExpression that doesn't have anything in its BindingExpressions collection
        // in the first place.  Added to which, there should be distinct error 
        // messages for both of these error conditions.
        if (MutableBindingExpressions.Count == 0)
            throw new InvalidOperationException(SR.Get(SRID.BindingExpressionIsDetached));
 
        UpdateTarget(true);
    } 
 
#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)
    {
            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 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 Properties
    // 
    //-----------------------------------------------------
 
    //----------------------------------------------------- 
    //
    //  Internal Methods 
    //
    //------------------------------------------------------

    // Create a new BindingExpression from the given Binding description 
    internal static MultiBindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, MultiBinding 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
        MultiBindingExpression bindExpr = new MultiBindingExpression(binding, owner); 

        // prevert transfers and updates until multiBindingExpression is ready 
        bindExpr.IsInTransfer = true; 
        bindExpr.IsInUpdate = true;
 
        bindExpr.ResolvePropertyDefaultSettings(binding.Mode, binding.UpdateSourceTrigger, fwMetaData);

        return bindExpr;
    } 

    // Attach to things that may require tree context (parent, root, etc.) 
    void AttachToContext(bool lastChance) 
    {
        DependencyObject target = TargetElement; 
        if (target == null)
            return;

        Debug.Assert(ParentMultiBinding.Converter != null, 
                "MultiBindingExpression should not exist if its bind does not have a valid converter.");
 
        bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.AttachToContext); 

        _converter = ParentMultiBinding.Converter; 
        if (_converter == null)
        {
            TraceData.Trace(TraceEventType.Error, TraceData.MultiBindingHasNoConverter, ParentMultiBinding);
        } 

        if (isExtendedTraceEnabled) 
        { 
            TraceData.Trace(TraceEventType.Warning,
                                TraceData.AttachToContext( 
                                    TraceData.Identify(this),
                                    lastChance ? " (last chance)" : String.Empty));
        }
 
        TransferIsDeferred = true;
        bool attached = true;       // true if all child bindings have attached 
        int count = MutableBindingExpressions.Count; 
        for (int i = 0; i < count; ++i)
        { 
            if (MutableBindingExpressions[i].Status == BindingStatus.Unattached)
                attached = false;
        }
 
        // if the child bindings aren't ready yet, try again later.  Leave
        // TransferIsDeferred set, to indicate we're not ready yet. 
        if (!attached && !lastChance) 
        {
            if (isExtendedTraceEnabled) 
            {
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.ChildNotAttached(
                                        TraceData.Identify(this))); 
            }
 
            return; 
        }
 
        // initial transfer
        TransferIsDeferred = false;
        EndSourceUpdate();              // now the MultiBindingExpression is ready for Transfers
        SetStatus(BindingStatus.Active); 

        if (!IsOneWayToSource) 
        { 
            UpdateTarget(false);
        } 
        else
        {
            IsInTransfer = false;       // set at creation time
            UpdateValue(); 
        }
    } 
 

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

    ///  
    ///     The ValidationError that caused this 
    ///     BindingExpression to be invalid.
    ///  
    public override ValidationError ValidationError
    {
        get
        { 
            ValidationError validationError = base.ValidationError;
 
            if (validationError == null) 
            {
                for ( int i = 0; i < MutableBindingExpressions.Count; i++ ) 
                {
                    validationError = MutableBindingExpressions[i].ValidationError;
                    if (validationError != null)
                        break; 
                }
            } 
 
            return validationError;
        } 
    }

    /// 
    ///     HasError returns true if any of the ValidationRules 
    ///     of any of its inner bindings failed its validation rule
    ///     or the Multi-/PriorityBinding itself has a failing validation rule. 
    ///  
    public override bool HasError
    { 
        get
        {
            bool hasError = base.HasError;
 
            if (!hasError)
            { 
                for ( int i = 0; i < MutableBindingExpressions.Count; i++ ) 
                {
                    if (MutableBindingExpressions[i].HasError) 
                        return true;
                }
            }
 
            return hasError;
        } 
    } 

    //------------------------------------------------------ 
    //
    //  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;
 
        // listen for lost focus
        if (IsUpdateOnLostFocus)
        {
            LostFocusEventManager.AddListener(target, this); 
        }
 
        TransferIsDeferred = true;          // Defer data transfer until after we activate all the BindingExpressions 
        int count = ParentMultiBinding.Bindings.Count;
        for (int i = 0; i < count; ++i) 
        {
            //

 
            AttachBindingExpression(i, false); // create new binding and have it added to end
        } 
 
        // 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(false /* lastChance */);
        if (TransferIsDeferred)
        { 
            Engine.AddTask(this, TaskOps.AttachToContext);
 
            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.AttachToContext)) 
            {
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.DeferAttachToContext(
                                        TraceData.Identify(this)));
            }
        } 
    }
 
    ///  sever all connections  
    internal override void DetachOverride()
    { 
        if (IsUpdateOnLostFocus)
        {
            LostFocusEventManager.RemoveListener(TargetElement, this);
        } 

        // Theoretically, we only need to detach number of AttentiveBindingExpressions, 
        // but we'll traverse the whole list anyway and do aggressive clean-up. 
        int count = MutableBindingExpressions.Count;
 
        for (int i = count - 1; i >= 0; i--)
        {
            BindingExpressionBase b = MutableBindingExpressions[i];
 
            if (b != null)
            { 
                b.Detach(); 
                MutableBindingExpressions.RemoveAt(i);
            } 
        }

        ChangeSources(null);
 
        base.DetachOverride();
    } 
 
    /// 
    /// Invalidate the given child expression. 
    /// 
    internal override void InvalidateChild(BindingExpressionBase bindingExpression)
    {
        int index = MutableBindingExpressions.IndexOf(bindingExpression); 

        // do a sanity check that we care about this BindingExpression 
        if (0 <= index && IsDynamic) 
        {
            NeedsDataTransfer = true; 
            Transfer();                 // this will Invalidate target property.
        }
    }
 
    /// 
    /// 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, MutableBindingExpressions.Count, 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)
        {
            // detach and clean up the old binding
            bindingExpression.Detach(); 

            // replace 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; }
    } 
 
    IMultiValueConverter Converter
    { 
        get { return _converter; }
        set { _converter = value; }
    }
 
    //-----------------------------------------------------
    // 
    //  Private Methods 
    //
    //----------------------------------------------------- 

    // Create a BindingExpression for position i
    BindingExpressionBase AttachBindingExpression(int i, bool replaceExisting)
    { 
        DependencyObject target = TargetElement;
        if (target == null) 
            return null; 

        BindingBase binding = ParentMultiBinding.Bindings[i]; 

        // Check if replacement bindings have the correct UpdateSourceTrigger
        MultiBinding.CheckTrigger(binding);
 
        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;
    } 

    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 = MutableBindingExpressions.Count;
 
        if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Events))
        { 
            TraceData.Trace(TraceEventType.Warning, 
                                TraceData.GotPropertyChanged(
                                    TraceData.Identify(this), 
                                    TraceData.Identify(d),
                                    dp.Name));
        }
 
        TransferIsDeferred = true;
        for (int i = 0; i < n; ++i) 
        { 
            BindingExpressionBase bindExpr = MutableBindingExpressions[i];
            if (bindExpr != null) 
            {
                DependencySource[] sources = bindExpr.GetSources();

                if (sources != null) 
                {
                    for (int j = 0; j < sources.Length; ++j) 
                    { 
                        DependencySource source = sources[j];
 
                        if (source.DependencyObject == d && source.DependencyProperty == dp)
                        {
                            bindExpr.OnPropertyInvalidation(d, args);
                            break; 
                        }
                    } 
                } 
            }
        } 

        TransferIsDeferred = false;
        Transfer();                 // Transfer if inner BindingExpressions have called Invalidate(binding)
    } 

    // invalidate the target property 
    void Invalidate() 
    {
        // 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) 
        {
            // recompute expression 
            target.InvalidateProperty(TargetProperty);
        }
    }
 
    /// 
    /// Handle events from the centralized event table 
    ///  
    internal override bool 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(LostFocusEventManager))
        {
            Update(true);
        } 
        else
        { 
            return base.ReceiveWeakEvent(managerType, sender, e); 
        }
 
        return true;
    }

#region Value 

    ///  Force a data transfer from source(s) to target  
    ///  
    ///     use true to propagate UpdateTarget call to all inner BindingExpressions;
    ///     use false to avoid forcing data re-transfer from one-time inner BindingExpressions 
    /// 
    void UpdateTarget(bool includeInnerBindings)
    {
        TransferIsDeferred = true; 

        if (includeInnerBindings) 
        { 
            foreach (BindingExpressionBase b in MutableBindingExpressions)
            { 
                b.UpdateTarget();
            }
        }
 
        TransferIsDeferred = false;
        NeedsDataTransfer = true;   // force data transfer 
        Transfer(); 
    }
 
    void Transfer()
    {
        // required state for transfer
        if (    NeedsDataTransfer       // Transfer is needed 
            &&  !IsInUpdate             // Not in an update
            &&  !TransferIsDeferred)    // Not aggregating transfers 
        { 
            TransferValue();
        } 
    }

    void TransferValue()
    { 
        IsInTransfer = true;
        NeedsDataTransfer = false; 
 
        DependencyObject target = TargetElement;
        if (target == null) 
            goto Done;

        bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Transfer);
 
        object value = DependencyProperty.UnsetValue;
        CultureInfo culture = GetCulture(); 
 
        // gather values from inner BindingExpressions
        int count = MutableBindingExpressions.Count; 
        for (int i = 0; i < count; ++i)
        {
            _tempValues[i] = MutableBindingExpressions[i].GetValue(target, TargetProperty); // could pass (null, null)
 
            if (isExtendedTraceEnabled)
            { 
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.GetRawValueMulti(
                                        TraceData.Identify(this), 
                                        i,
                                        TraceData.Identify(_tempValues[i])));
            }
        } 

        Debug.Assert(ParentMultiBinding.Converter != null, "MultiBindingExpression's ParentMultiBinding has no Converter."); 
 
        if (Converter != null)
        { 
            // MultiValueConverters are always user-defined, so don't catch exceptions (bug 992237)
            value = Converter.Convert(_tempValues, TargetProperty.PropertyType, ParentMultiBinding.ConverterParameter, culture);

            if (isExtendedTraceEnabled) 
            {
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.UserConverter( 
                                        TraceData.Identify(this),
                                        TraceData.Identify(value))); 
            }
        }
        else    // no converter (perhaps user specified it in error)
        { 
            if (TraceData.IsEnabled)
            { 
                TraceData.Trace(TraceEventType.Error, TraceData.MultiValueConverterMissingForTransfer, this); 
            }
 
            goto Done;
        }

        Array.Clear(_tempValues, 0, _tempValues.Length); 

        // the special value DoNothing means no error, but no data transfer 
        if (value == Binding.DoNothing) 
            goto Done;
 
        // if the value isn't acceptable to the target property, don't use it
        if (value != DependencyProperty.UnsetValue && !TargetProperty.IsValidValue(value))
        {
            if (TraceData.IsEnabled) 
            {
                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 we can't obtain a value, try the fallback value.
        if (value == DependencyProperty.UnsetValue)
        { 
            value = UseFallbackValue();
 
            if (isExtendedTraceEnabled) 
            {
                TraceData.Trace(TraceEventType.Warning, 
                                    TraceData.UseFallback(
                                        TraceData.Identify(this),
                                        TraceData.Identify(value)));
            } 
        }
 
        if (isExtendedTraceEnabled) 
        {
            TraceData.Trace(TraceEventType.Warning, 
                                TraceData.TransferValue(
                                    TraceData.Identify(this),
                                    TraceData.Identify(value)));
        } 

        // update the cached value 
        ChangeValue(value, true); 
        Invalidate();
 
        OnTargetUpdated();
        Validation.ClearInvalid(this);

    Done: 
        IsInTransfer = false;
    } 
 
    void OnTargetUpdated()
    { 
        if (NotifyOnTargetUpdated)
        {
            DependencyObject target = TargetElement;
            if (target != null) 
            {
                // 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
                { 
                    BindingExpression.OnTargetUpdated(target, TargetProperty); 
                }
            } 
        }
    }

    void OnSourceUpdated() 
    {
        if (NotifyOnSourceUpdated) 
        { 
            DependencyObject target = TargetElement;
            if (target != null) 
            {
                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
            ) 
            return;
 
        if (synchronous) 
        {
            UpdateValue(); 
        }
        else
        {
            Engine.AddTask(this, TaskOps.UpdateValue); 
        }
    } 
 
    void UpdateValue()
    { 
        object value;
        DependencyObject target = TargetElement;

        if (target == null) 
            return;
 
        Debug.Assert(ParentMultiBinding.Converter != null, "MultiBindingExpression's ParentMultiBinding has no Converter."); 
        Debug.Assert(Converter != null, "UpdateValue is being called before MultiBindingExpression is ready.");
 
        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);
 
        Collection validationRules = ParentMultiBinding.ValidationRulesInternal;
 
        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)  // This is a paranoid check. There should always be a Converter.
        {
            int count = MutableBindingExpressions.Count; 
            value = Value;
            object[] values = null; 
            Exception exception = null; 

            for (int i = 0; i < count; ++i) 
            {
                BindingExpressionBase bindExpr = MutableBindingExpressions[i];
                BindingExpression be = bindExpr as BindingExpression;
 
                if (be != null && be.UseDefaultValueConverter)
                    _tempTypes[i] = be.ConverterSourceType; 
                else 
                    _tempTypes[i] = TargetProperty.PropertyType;
            } 

            // MultiValueConverters are always user-defined, so don't catch exceptions (bug 992237)
            values = Converter.ConvertBack(value, _tempTypes, ParentMultiBinding.ConverterParameter, culture);
 
            if (values == null)
            { 
                if (TraceData.IsEnabled) 
                {
                    TraceData.Trace(TraceEventType.Error, 
                        TraceData.BadMultiConverterForUpdate(
                            Converter.GetType().Name,
                            AvTrace.ToStringHelper(value),
                            AvTrace.TypeName(value)), 
                        this, exception);
                } 
                return; 
            }
 
            if (isExtendedTraceEnabled)
            {
                for (int i=0; i  _list = new Collection();
    IMultiValueConverter    _converter;
    object[]                _tempValues; 
    Type[]                  _tempTypes;
} 
 
}

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