Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Data / BindingExpressionBase.cs / 8 / BindingExpressionBase.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Defines BindingExpressionBase object, // base class for BindingExpression, PriorityBindingExpression, // and MultiBindingExpression. // // See spec at [....]/connecteddata/Specs/Data%20Binding.mht // //--------------------------------------------------------------------------- // build with this symbol defined to catch errors about not using // BindingExpression.GetReference correctly //#define USE_ITEM_REFERENCE using System; using System.Collections.ObjectModel; // Collectionusing System.ComponentModel; // TypeConverter using System.Diagnostics; // StackTrace using System.Globalization; // CultureInfo using System.Windows; // FrameworkElement using System.Windows.Controls; // Validation using System.Windows.Markup; // XmlLanguage using System.Windows.Threading; // Dispatcher using MS.Internal; // Invariant.Assert using MS.Internal.Controls; // ValidationErrorCollection using MS.Internal.Data; // DataBindEngine using MS.Internal.KnownBoxes; // BooleanBoxes using MS.Internal.Utility; // TraceLog namespace System.Windows.Data { /// /// Base class for Binding Expressions. /// public abstract class BindingExpressionBase : Expression, IWeakEventListener { // Flags indicating run-time properties of a BindingExpression [Flags] internal enum BindingFlags { // names used by Binding OneWay = PrivateFlags.iSourceToTarget, TwoWay = PrivateFlags.iSourceToTarget | PrivateFlags.iTargetToSource, OneWayToSource = PrivateFlags.iTargetToSource, OneTime = 0, PropDefault = PrivateFlags.iPropDefault, NotifyOnTargetUpdated = PrivateFlags.iNotifyOnTargetUpdated, NotifyOnSourceUpdated = PrivateFlags.iNotifyOnSourceUpdated, NotifyOnValidationError = PrivateFlags.iNotifyOnValidationError, UpdateOnPropertyChanged = 0, UpdateOnLostFocus = PrivateFlags.iUpdateOnLostFocus, UpdateExplicitly = PrivateFlags.iUpdateExplicitly, UpdateDefault = PrivateFlags.iUpdateDefault, PathGeneratedInternally = PrivateFlags.iPathGeneratedInternally, ValidatesOnExceptions = PrivateFlags.iValidatesOnExceptions, ValidatesOnDataErrors = PrivateFlags.iValidatesOnDataErrors, Default = PropDefault | UpdateDefault, ///Error value, returned by FlagsFrom to indicate faulty input IllegalInput = PrivateFlags.iIllegalInput, PropagationMask = OneWay | TwoWay | OneWayToSource | OneTime | PropDefault, UpdateMask = UpdateOnPropertyChanged | UpdateOnLostFocus | UpdateExplicitly | UpdateDefault, } [Flags] private enum PrivateFlags { // internal use iSourceToTarget = 0x00000001, iTargetToSource = 0x00000002, iPropDefault = 0x00000004, iNotifyOnTargetUpdated = 0x00000008, iDefaultValueConverter = 0x00000010, iInTransfer = 0x00000020, iInUpdate = 0x00000040, iTransferPending = 0x00000080, iNeedDataTransfer = 0x00000100, iTransferDeferred = 0x00000200, // used by MultiBindingExpression iUpdateOnLostFocus = 0x00000400, iUpdateExplicitly = 0x00000800, iUpdateDefault = iUpdateExplicitly | iUpdateOnLostFocus, iNeedUpdate = 0x00001000, iPathGeneratedInternally = 0x00002000, iUsingMentor = 0x00004000, iResolveNamesInTemplate = 0x00008000, iDetaching = 0x00010000, iNeedsCollectionView = 0x00020000, iInPriorityBindingExpression= 0x00040000, iInMultiBindingExpression = 0x00080000, iUsingFallbackValue = 0x00100000, iNotifyOnValidationError = 0x00200000, iAttaching = 0x00400000, iNotifyOnSourceUpdated = 0x00800000, iValidatesOnExceptions = 0x01000000, iValidatesOnDataErrors = 0x02000000, iIllegalInput = 0x40000000, iPropagationMask = iSourceToTarget | iTargetToSource | iPropDefault, iUpdateMask = iUpdateOnLostFocus | iUpdateExplicitly, } //----------------------------------------------------- // // Constructors // //----------------------------------------------------- ///Constructor internal BindingExpressionBase(BindingBase binding, BindingExpressionBase parent) : base(ExpressionMode.SupportsUnboundSources) { if (binding == null) throw new ArgumentNullException("binding"); _binding = binding; _parentBindingExpression = parent; _flags = (PrivateFlags)binding.Flags; if (parent != null) { Type type = parent.GetType(); if (type == typeof(MultiBindingExpression)) ChangeFlag(PrivateFlags.iInMultiBindingExpression, true); else if (type == typeof(PriorityBindingExpression)) ChangeFlag(PrivateFlags.iInPriorityBindingExpression, true); } // initialize tracing information PresentationTraceLevel traceLevel = PresentationTraceSources.GetTraceLevel(binding); if (traceLevel > 0) { // copy TraceLevel from parent BindingBase - it can be changed later PresentationTraceSources.SetTraceLevel(this, traceLevel); } if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.CreateExpression)) { if (parent == null) { TraceData.Trace(TraceEventType.Warning, TraceData.CreatedExpression( TraceData.Identify(this), TraceData.Identify(binding))); } else { TraceData.Trace(TraceEventType.Warning, TraceData.CreatedExpressionInParent( TraceData.Identify(this), TraceData.Identify(binding), TraceData.Identify(parent))); } } if (LookupValidationRule(typeof(ExceptionValidationRule)) != null) { ChangeFlag(PrivateFlags.iValidatesOnExceptions, true); } if (LookupValidationRule(typeof(DataErrorValidationRule)) != null) { ChangeFlag(PrivateFlags.iValidatesOnDataErrors, true); } } //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- ///Binding from which this expression was created public BindingBase ParentBindingBase { get { return _binding; } } ///Status of the BindingExpression public BindingStatus Status { get { return _status; } } ////// The ValidationError that caused this /// BindingExpression to be invalid. /// public virtual ValidationError ValidationError { get { return _validationError; } } ////// HasError returns true if any of the ValidationRules /// in the ParentBinding failed its validation rule. /// public virtual bool HasError { get { return _validationError != null; } } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ ///Force a data transfer from source to target public virtual void UpdateTarget() { } ///Send the current value back to the source ///Does nothing when binding's Mode is not TwoWay or OneWayToSource public virtual void UpdateSource() { } #region Expression overrides ////// Notification that the Expression has been set as a property's value /// ////// Subclasses should not override OnAttach(), but must override Attach() /// /// DependencyObject being set /// Property being set internal sealed override void OnAttach(DependencyObject d, DependencyProperty dp) { if (d == null) throw new ArgumentNullException("d"); if (dp == null) throw new ArgumentNullException("dp"); Attach(d, dp); } ////// Notification that the Expression has been removed as a property's value /// ////// Subclasses should not override OnDetach(), but must override Detach() /// /// DependencyObject being cleared /// Property being cleared internal sealed override void OnDetach(DependencyObject d, DependencyProperty dp) { Detach(); } ////// List of sources of the Expression /// ///Sources list internal override DependencySource[] GetSources() { int j, k; int n = (_sources != null) ? _sources.Length : 0; if (n == 0) return null; DependencySource[] result = new DependencySource[n]; // convert the weak references into strong ones for (j=0, k=0; k/// Handle events from the centralized event table /// bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { return ReceiveWeakEvent(managerType, sender, e); } #region BindingExpressions with no target DP //----------------------------------------------------- // // API for BindingExpressions with no target DP (task 20769) // This is internal for now, until we review whether we wish to // make it public // //------------------------------------------------------ /// Create an untargeted BindingExpression internal static BindingExpressionBase CreateUntargetedBindingExpression(DependencyObject d, BindingBase binding) { return binding.CreateBindingExpression(d, NoTargetProperty); } ///Attach the BindingExpression to its target element ////// This method must be called once during the initialization. /// /// The target element internal void Attach(DependencyObject d) { Attach(d, NoTargetProperty); } ///This event is raised when the BindingExpression's value changes internal event EventHandlerValueChanged; /* The following APIs are also needed for untargeted bindings, but they already exist for other reasons. /// The current value of the BindingExpression internal object Value { get; set; } ///Activate the BindingExpression, using the given item as its root item. internal void Activate(object item) {} ///Deactivate the BindingExpression. internal void Deactivate() {} ///Detach the BindingExpression from its target element ////// This method must be called once when the BindingExpression is no longer needed. /// internal void Detach() {} */ #endregion BindingExpressions with no target DP //----------------------------------------------------- // // Protected Properties // //----------------------------------------------------- ///True if this binding expression is attaching internal bool IsAttaching { get { return TestFlag(PrivateFlags.iAttaching); } set { ChangeFlag(PrivateFlags.iAttaching, value); } } ///True if this binding expression is detaching internal bool IsDetaching { get { return TestFlag(PrivateFlags.iDetaching); } set { ChangeFlag(PrivateFlags.iDetaching, value); } } ///True if this binding expression updates the target internal bool IsDynamic { get { return ( TestFlag(PrivateFlags.iSourceToTarget) && (!IsInMultiBindingExpression || ParentMultiBindingExpression.IsDynamic)); } } ///True if this binding expression updates the source internal bool IsReflective { get { return ( TestFlag(PrivateFlags.iTargetToSource) && (!IsInMultiBindingExpression || ParentMultiBindingExpression.IsReflective)); } set { ChangeFlag(PrivateFlags.iTargetToSource, value); } } ///True if this binding expression uses a default ValueConverter internal bool UseDefaultValueConverter { get { return TestFlag(PrivateFlags.iDefaultValueConverter); } set { ChangeFlag(PrivateFlags.iDefaultValueConverter, value); } } ///True if this binding expression is OneWayToSource internal bool IsOneWayToSource { get { return (_flags & PrivateFlags.iPropagationMask) == PrivateFlags.iTargetToSource; } } ///True if this binding expression updates on PropertyChanged internal bool IsUpdateOnPropertyChanged { get { return (_flags & PrivateFlags.iUpdateMask) == 0; } } ///True if this binding expression updates on LostFocus internal bool IsUpdateOnLostFocus { get { return TestFlag(PrivateFlags.iUpdateOnLostFocus); } } ///True if this binding expression has a pending target update internal bool IsTransferPending { get { return TestFlag(PrivateFlags.iTransferPending); } set { ChangeFlag(PrivateFlags.iTransferPending, value); } } ///True if this binding expression is deferring a target update internal bool TransferIsDeferred { get { return TestFlag(PrivateFlags.iTransferDeferred); } set { ChangeFlag(PrivateFlags.iTransferDeferred, value); } } ///True if this binding expression is updating the target internal bool IsInTransfer { get { return TestFlag(PrivateFlags.iInTransfer); } set { ChangeFlag(PrivateFlags.iInTransfer, value); } } ///True if this binding expression is updating the source internal bool IsInUpdate { get { return TestFlag(PrivateFlags.iInUpdate); } set { ChangeFlag(PrivateFlags.iInUpdate, value); } } ///True if this binding expression is using the fallback value internal bool UsingFallbackValue { get { return TestFlag(PrivateFlags.iUsingFallbackValue); } set { ChangeFlag(PrivateFlags.iUsingFallbackValue, value); } } ///True if this binding expression uses the mentor of the target element internal bool UsingMentor { get { return TestFlag(PrivateFlags.iUsingMentor); } set { ChangeFlag(PrivateFlags.iUsingMentor, value); } } ///True if this binding expression should resolve ElementName within the template of the target element internal bool ResolveNamesInTemplate { get { return TestFlag(PrivateFlags.iResolveNamesInTemplate); } set { ChangeFlag(PrivateFlags.iResolveNamesInTemplate, value); } } ///True if this binding expression has a pending target update internal bool NeedsDataTransfer { get { return TestFlag(PrivateFlags.iNeedDataTransfer); } set { ChangeFlag(PrivateFlags.iNeedDataTransfer, value); } } ///True if this binding expression has a pending source update internal bool NeedsUpdate { get { return TestFlag(PrivateFlags.iNeedUpdate); } set { ChangeFlag(PrivateFlags.iNeedUpdate, value); } } ///True if this binding expression should raise the TargetUpdated event internal bool NotifyOnTargetUpdated { get { return TestFlag(PrivateFlags.iNotifyOnTargetUpdated); } set { ChangeFlag(PrivateFlags.iNotifyOnTargetUpdated, value); } } ///True if this binding expression should raise the SourceUpdated event internal bool NotifyOnSourceUpdated { get { return TestFlag(PrivateFlags.iNotifyOnSourceUpdated); } set { ChangeFlag(PrivateFlags.iNotifyOnSourceUpdated, value); } } ///True if this binding expression should raise the ValidationError event internal bool NotifyOnValidationError { get { return TestFlag(PrivateFlags.iNotifyOnValidationError); } set { ChangeFlag(PrivateFlags.iNotifyOnValidationError, value); } } ///True if this binding expression belongs to a PriorityBinding internal bool IsInPriorityBindingExpression { get { return TestFlag(PrivateFlags.iInPriorityBindingExpression); } } ///True if this binding expression belongs to a MultiBinding internal bool IsInMultiBindingExpression { get { return TestFlag(PrivateFlags.iInMultiBindingExpression); } } ///True if this binding expression belongs to a PriorityBinding or MultiBinding internal bool IsInBindingExpressionCollection { get { return TestFlag(PrivateFlags.iInPriorityBindingExpression | PrivateFlags.iInMultiBindingExpression); } } ///True if this binding expression validates on exceptions internal bool ValidatesOnExceptions { get { return TestFlag(PrivateFlags.iValidatesOnExceptions); } } ///True if this binding expression validates on data errors internal bool ValidatesOnDataErrors { get { return TestFlag(PrivateFlags.iValidatesOnDataErrors); } } ///The parent MultiBindingExpression (if any) internal MultiBindingExpression ParentMultiBindingExpression { get { return _parentBindingExpression as MultiBindingExpression; } } ///The parent PriorityBindingExpression (if any) internal PriorityBindingExpression ParentPriorityBindingExpression { get { return _parentBindingExpression as PriorityBindingExpression; } } ///The parent PriorityBindingExpression or MultiBindingExpression (if any) internal BindingExpressionBase ParentBindingExpressionBase { get { return _parentBindingExpression; } } ///The FallbackValue (from the parent Binding), possibly converted /// to a type suitable for the target property. internal object FallbackValue { // perf note: we recompute the value every time it's needed. This is // a good decision if we seldom need the value. Alternatively we could // cache it. Wait until we know what the perf impact really is. get { return ConvertFallbackValue(ParentBindingBase.FallbackValue, TargetProperty, this); } } ///The default value of the target property internal object DefaultValue { // perf note: we recompute the value every time it's needed. This is // a good decision if we seldom need the value. Alternatively we could // cache it. Wait until we know what the perf impact really is. get { DependencyObject target = TargetElement; if (target != null) { return TargetProperty.GetDefaultValue(target.DependencyObjectType); } return DependencyProperty.UnsetValue; } } //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ ////// Attach the binding expression to the given target object and property. /// Derived classes should call base.AttachOverride before doing their work. /// internal virtual void AttachOverride(DependencyObject target, DependencyProperty dp) { _targetElement = new WeakReference(target); _targetProperty = dp; // get the engine _engine = DataBindEngine.CurrentDataBindEngine; if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Attach)) { TraceData.Trace(TraceEventType.Warning, TraceData.AttachExpression( TraceData.Identify(this), target.GetType().FullName, dp.Name, AvTrace.GetHashCodeHelper(target))); } } ////// Detach the binding expression from its target object and property. /// Derived classes should call base.DetachOverride after doing their work. /// internal virtual void DetachOverride() { _engine = null; _targetElement = null; _targetProperty = null; SetStatus(BindingStatus.Detached); if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.Attach)) { TraceData.Trace(TraceEventType.Warning, TraceData.DetachExpression( TraceData.Identify(this))); } } ////// Invalidate the given child expression. /// internal abstract void InvalidateChild(BindingExpressionBase bindingExpression); ////// Change the dependency sources for the given child expression. /// internal abstract void ChangeSourcesForChild(BindingExpressionBase bindingExpression, WeakDependencySource[] newSources); ////// Replace the given child expression with a new one. /// internal abstract void ReplaceChild(BindingExpressionBase bindingExpression); ////// Compute the culture, either from the parent Binding, or from the target element. /// internal CultureInfo GetCulture() { // lazy initialization, to let the target element acquire all its properties if (_culture == DefaultValueObject) { // explicit culture set in Binding _culture = ParentBindingBase.ConverterCultureInternal; // if that doesn't work, use target element's xml:lang property if (_culture == null) { DependencyObject target = TargetElement; if (target != null) { if (IsInTransfer && (TargetProperty == FrameworkElement.LanguageProperty)) { // A binding for the Language property needs the value // of the Language property. This circularity is not // supported (bug 1274874). if (TraceData.IsEnabled) { TraceData.Trace(TraceEventType.Critical, TraceData.RequiresExplicitCulture, TargetProperty.Name, this); } throw new InvalidOperationException(SR.Get(SRID.RequiresExplicitCulture, TargetProperty.Name)); } // cache CultureInfo since requerying an inheritable property on every Transfer/Update can be quite expensive // CultureInfo DP rarely changes once a XAML document is loaded. // To be 100% correct, changes to the CultureInfo attached DP should be tracked // and cause a re-evaluation of this binding. _culture = ((XmlLanguage) target.GetValue(FrameworkElement.LanguageProperty)).GetSpecificCulture(); } } } return (CultureInfo)_culture; } ///Begin a source update internal void BeginSourceUpdate() { ChangeFlag(PrivateFlags.iInUpdate, true); } ///End a source update internal void EndSourceUpdate() { ChangeFlag(PrivateFlags.iInUpdate | PrivateFlags.iNeedUpdate, false); } ///change the value to the new value, and notify listeners internal void ChangeValue(object newValue, bool notify) { object oldValue = (_value != DefaultValueObject) ? _value : DependencyProperty.UnsetValue; _value = newValue; if (notify && ValueChanged != null) { ValueChanged(this, new BindingValueChangedEventArgs(oldValue, newValue)); } } ///the target value has changed - the source needs to be updated internal void Dirty() { if (!IsInTransfer) { NeedsUpdate = true; if (IsUpdateOnPropertyChanged) Update(true); } } ///use the Fallback or Default value, called when a real value is not available internal object UseFallbackValue() { object value = FallbackValue; // if there's a problem with the fallback, use Default instead if (value == DefaultValueObject) { value = DependencyProperty.UnsetValue; } if (value != DependencyProperty.UnsetValue) { UsingFallbackValue = true; } else { // if fallback isn't available, use Default (except when in a binding collection) if (Status == BindingStatus.Active) SetStatus(BindingStatus.UpdateTargetError); if (!IsInBindingExpressionCollection) { value = DefaultValue; if (TraceData.IsEnabled) { TraceData.Trace(TraceEventType.Information, TraceData.NoValueToTransfer, this); } } } return value; } internal ValidationRule LookupValidationRule(Type type) { ValidationRule result = ParentBindingBase.GetValidationRule(type); if (result == null && _parentBindingExpression != null) { result = _parentBindingExpression.LookupValidationRule(type); } return result; } ////// Handle events from the centralized event table /// internal virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { return false; // unrecognized event } private bool TestFlag(PrivateFlags flag) { return (_flags & flag) != 0; } private void ChangeFlag(PrivateFlags flag, bool value) { if (value) _flags |= flag; else _flags &= ~flag; } //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ internal DependencyProperty TargetProperty { get { return _targetProperty; } } // A BindingExpression cannot hold a strong reference to the target element - this // leads to memory leaks (bug 871139). The problem is that BindingExpression and its workers // register for events from the data item, creating a reference from // the data item to the BindingExpression. The data item typically has a long lifetime, // so if the BindingExpression held a SR to the target, the target element would // also stay alive forever. // Instead, BindingExpression holds a WeakReference to the target. This means we // have to check it before dereferencing (here), and cope when the // reference fails (in callers to this property). Requests for the TargetElement // are not trivial, so callers should request it once and cache the result // in a local variable. They should not save it in a global or instance // variable of course; that would defeat the purpose of the WR. // This allows the target element to be GC'd when it's no longer in // use by the tree or application. The next time the BindingExpression asks for // its TargetElement, the WR will fail. At this point, the BindingExpression is no // longer useful, so it can sever all connections to the outside world (i.e. // stop listening for events). This allows the BindingExpression itself to be GC'd. internal DependencyObject TargetElement { get { if (_targetElement != null) { DependencyObject result = _targetElement.Target as DependencyObject; if (result != null) return result; // target has been GC'd, sever all connections _targetElement = null; // prevents re-entry from Detach() Detach(); } return null; } } internal WeakReference TargetElementReference { get { return _targetElement; } } internal DataBindEngine Engine { get { return _engine; } } internal Dispatcher Dispatcher { get { return (_engine != null) ? _engine.Dispatcher : null; } } internal object Value { get { if (_value == DefaultValueObject) { // don't notify listeners. This isn't a real value change. ChangeValue(UseFallbackValue(), false /*notify*/); } return _value; } set { ChangeValue(value, true); Dirty(); } } internal WeakDependencySource[] WeakSources { get { return _sources; } } ////// NoTarget DependencyProperty, a placeholder used by BindingExpressions with no target property /// internal static readonly DependencyProperty NoTargetProperty = DependencyProperty.RegisterAttached("NoTarget", typeof(object), typeof(BindingExpressionBase), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None)); internal TraceLog TraceLog { get { return _traceLog; } } //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- ////// Attach the binding expression to the given target object and property. /// internal void Attach(DependencyObject target, DependencyProperty dp) { // make sure we're on the right thread to access the target if (target != null) { target.VerifyAccess(); } IsAttaching = true; AttachOverride(target, dp); IsAttaching = false; } ////// Detach the binding expression from its target object and property. /// internal void Detach() { if (_status == BindingStatus.Detached || IsDetaching) return; IsDetaching = true; DetachOverride(); IsDetaching = false; } internal void SetStatus(BindingStatus status) { if (_status == BindingStatus.Detached && status != _status) { throw new InvalidOperationException(SR.Get(SRID.BindingExpressionStatusChanged, _status, status)); } _status = status; if (_traceLog != null) { _traceLog.Add("Set status = {0} {1}", _status, new StackTrace()); } } // convert a user-supplied fallback value to a usable equivalent // returns: UnsetValue if user did not supply a fallback value // value if fallback value is legal // DefaultValueObject otherwise internal static object ConvertFallbackValue(object value, DependencyProperty dp, object sender) { object result; if (value == DependencyProperty.UnsetValue || dp.IsValidValue(value)) { result = value; } else { result = null; // placeholder to keep compiler happy // if value isn't the right type, use a type converter to get a better value bool success = false; Exception e = null; TypeConverter converter = DefaultValueConverter.GetConverter(dp.PropertyType); if (converter != null && converter.CanConvertFrom(value.GetType())) { // PreSharp uses message numbers that the C# compiler doesn't know about. // Disable the C# complaints, per the PreSharp documentation. #pragma warning disable 1634, 1691 // PreSharp complains about catching NullReference (and other) exceptions. // It doesn't recognize that IsCriticalException() handles these correctly. #pragma warning disable 56500 try { result = converter.ConvertFrom(null, CultureInfo.InvariantCulture, value); success = dp.IsValidValue(result); } // Catch all exceptions. If we can't convert the fallback value, it doesn't // matter why not; we should always use the default value instead. // (See bug 1853628 for an example of a converter that throws // an exception not mentioned in the documentation for ConvertFrom.) catch (Exception ex) { e = ex; } catch // non CLS compliant exception { } #pragma warning restore 56500 #pragma warning restore 1634, 1691 } if (!success) { // if can't convert it, don't use it result = DefaultValueObject; if (TraceData.IsEnabled) { TraceData.Trace(TraceEventType.Error, TraceData.FallbackConversionFailed( AvTrace.ToStringHelper(value), AvTrace.TypeName(value), dp.Name, dp.PropertyType.Name), sender, e); } } } return result; } // Certain trace reports should be marked as 'error' unless the binding // is prepared to handle it in some way (e.g. FallbackValue), in which // case 'warning'. internal TraceEventType TraceLevel { get { // FallbackValue is present if (ParentBindingBase.FallbackValue != DependencyProperty.UnsetValue) return TraceEventType.Warning; // Binding is a member of MultiBinding or PriorityBinding if (IsInBindingExpressionCollection) return TraceEventType.Warning; // all other cases - error return TraceEventType.Error; } } internal virtual void Activate() { } internal virtual void Deactivate() { } internal virtual void Update(bool synchronous) { } internal void UpdateValidationError(ValidationError validationError) { DependencyObject targetElement = TargetElement; bool shouldRaiseEvent = NotifyOnValidationError; ValidationError oldValidationError = _validationError; if (targetElement != null) { ValidationErrorCollection validationErrors = Validation.GetErrorsInternal(targetElement); bool oldInvalid = (validationErrors != null && validationErrors.Count > 0); // If there is currently a _validationError, then we will be clearing // it (at least temporarily). if (_validationError != null) { Invariant.Assert(validationErrors != null && validationErrors.Count > 0, "The validationErrors collection should not be either null or empty if there is a BindingExpression with a ValidationError"); if (validationErrors.Count > 0) { validationErrors.Remove(_validationError); _validationError = null; // if the count is 0 here, then that // means that we have gone from invalid to valid. if (validationErrors.Count == 0) { targetElement.ClearValue(Validation.HasErrorPropertyKey); } if (shouldRaiseEvent) { OnValidationError(targetElement, oldValidationError, ValidationErrorEventAction.Removed); } } } if (validationError != null) { if (validationErrors == null) { validationErrors = new ValidationErrorCollection(); validationErrors.Add(validationError); targetElement.SetValue(Validation.ValidationErrorsInternalProperty, validationErrors); } else { validationErrors.Add(validationError); } _validationError = validationError; // if the count is 1 here, then that // means that we have gone from valid to invalid. if (validationErrors.Count == 1) { targetElement.SetValue(Validation.HasErrorPropertyKey, BooleanBoxes.TrueBox); } if (shouldRaiseEvent) { OnValidationError(targetElement, _validationError, ValidationErrorEventAction.Added); } } bool invalid = (validationErrors != null && validationErrors.Count > 0); if (!invalid && oldInvalid) { targetElement.ClearValue(Validation.ValidationErrorsInternalProperty); } if (invalid || oldInvalid) { Validation.ShowValidationAdorner(targetElement, invalid); } } GC.KeepAlive(targetElement); // keep target alive during activation (bug 956831) } internal static void OnValidationError(DependencyObject source, ValidationError validationError, ValidationErrorEventAction action) { ValidationErrorEventArgs args = new ValidationErrorEventArgs(validationError, action); if (source is ContentElement) ((ContentElement)source).RaiseEvent(args); else if (source is UIElement) ((UIElement)source).RaiseEvent(args); else if (source is UIElement3D) ((UIElement3D)source).RaiseEvent(args); } internal void ChangeSources(WeakDependencySource[] newSources) { DependencyObject target = TargetElement; if (target != null) { if (IsInBindingExpressionCollection) ParentBindingExpressionBase.ChangeSourcesForChild(this, newSources); else ChangeSources(target, TargetProperty, newSources); } // store the sources with weak refs, so they don't cause memory leaks (bug 980041) _sources = newSources; } ////// combine the sources of BindingExpressions, using new sources for /// the BindingExpression at the given index /// /// -1 to indicate no new sources /// collection of child binding expressions /// how many child expressions to include /// use null when no new sources ///internal static WeakDependencySource[] CombineSources(int index, Collection bindingExpressions, int count, WeakDependencySource[] newSources) { if (index == count) { // Be sure to include newSources if they are being appended count++; } Collection tempList = new Collection (); for (int i = 0; i < count; ++i) { BindingExpressionBase bindExpr = bindingExpressions[i]; WeakDependencySource[] sources = (i==index) ? newSources : (bindExpr != null) ? bindExpr.WeakSources : null; int m = (sources == null) ? 0 : sources.Length; for (int j = 0; j < m; ++j) { WeakDependencySource candidate = sources[j]; // don't add duplicate source for (int k = 0; k < tempList.Count; ++k) { WeakDependencySource prior = tempList[k]; if (candidate.DependencyObject == prior.DependencyObject && candidate.DependencyProperty == prior.DependencyProperty) { candidate = null; break; } } if (candidate != null) tempList.Add(candidate); } } WeakDependencySource[] result; if (tempList.Count > 0) { result = new WeakDependencySource[tempList.Count]; tempList.CopyTo(result, 0); tempList.Clear(); } else { result = null; } return result; } internal void ResolvePropertyDefaultSettings(BindingMode mode, UpdateSourceTrigger updateTrigger, FrameworkPropertyMetadata fwMetaData) { // resolve "property-default" dataflow if (mode == BindingMode.Default) { BindingFlags f = BindingFlags.OneWay; if (fwMetaData != null && fwMetaData.BindsTwoWayByDefault) { f = BindingFlags.TwoWay; } ChangeFlag(PrivateFlags.iPropagationMask, false); ChangeFlag((PrivateFlags)f, true); if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ResolveDefaults)) { TraceData.Trace(TraceEventType.Warning, TraceData.ResolveDefaultMode( TraceData.Identify(this), (f == BindingFlags.OneWay) ? BindingMode.OneWay : BindingMode.TwoWay)); } } Debug.Assert((_flags & PrivateFlags.iPropagationMask) != PrivateFlags.iPropDefault, "BindingExpression should not have Default propagation"); // resolve "property-default" update trigger if (updateTrigger == UpdateSourceTrigger.Default) { UpdateSourceTrigger ust = IsInMultiBindingExpression ? UpdateSourceTrigger.Explicit : (fwMetaData != null) ? fwMetaData.DefaultUpdateSourceTrigger : UpdateSourceTrigger.PropertyChanged; ChangeFlag(PrivateFlags.iUpdateMask, false); ChangeFlag((PrivateFlags)BindingBase.FlagsFrom(ust), true); if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ResolveDefaults)) { TraceData.Trace(TraceEventType.Warning, TraceData.ResolveDefaultUpdate( TraceData.Identify(this), ust)); } } Invariant.Assert((_flags & PrivateFlags.iUpdateMask) != PrivateFlags.iUpdateDefault, "BindingExpression should not have Default update trigger"); } // To prevent memory leaks, we store WeakReferences to certain objects // in various places: _dataItem, _sources, worker fields. The logic // for this is centralized in these two static methods. (See bug 940041) internal static object CreateReference(object item) { // One source of leaks is the reference cycle formed when a BindingExpression's // source item contains a reference chain to the target element: // target -> BindingExpression -> source item -> target // // Making the second link into a WeakReference incurs some cost, // so it should be avoided if we know the third link never exists. // We definitely can't avoid this when the item is a DependencyObject, // since it's reasonably common for the third link to occur (e.g. // a ContextMenu contains a link to its Popup, which has a property // bound back to the ContextMenu). // // For safety, we choose to use WeakRef all the time, unless the item is null. // Exception (bug 1124954): Keep a strong reference to // BindingListCollectionView - this keeps the underlying DataView // alive, when nobody else will. // Exception (bug 1970505): Don't allocate a WeakRef for the common // case of the NullDataItem if (item != null && !(item is BindingListCollectionView) && !(item == BindingExpression.NullDataItem)) { item = new WeakReference(item); } #if USE_ITEM_REFERENCE item = new ItemReference(item); #endif return item; } // like CreateReference, but use an existing WeakReference internal static object CreateReference(WeakReference item) { object result = item; #if USE_ITEM_REFERENCE result = new ItemReference(item); #endif return result; } // like CreateReference, except re-target the old WeakReference (if any) internal static object ReplaceReference(object oldReference, object item) { if (item != null && !(item is BindingListCollectionView) && !(item == BindingExpression.NullDataItem)) { #if USE_ITEM_REFERENCE // if this cast fails, it's because you have done a direct assignment of an // item to some field instead of assigning the result of CreateReference. oldReference = ((ItemReference)oldReference).Item; #endif WeakReference wr = oldReference as WeakReference; if (wr != null) { wr.Target = item; item = wr; } else { item = new WeakReference(item); } } #if USE_ITEM_REFERENCE item = new ItemReference(item); #endif return item; } internal static object GetReference(object reference) { if (reference == null) return null; #if USE_ITEM_REFERENCE // if this cast fails, it's because you have done a direct assignment of an // item to some field instead of assigning the result of CreateReference. reference = ((ItemReference)reference).Item; #endif WeakReference wr = reference as WeakReference; if (wr != null) return wr.Target; else return reference; } internal static void InitializeTracing(BindingExpressionBase expr, DependencyObject d, DependencyProperty dp) { BindingBase parent = expr.ParentBindingBase; } //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #if USE_ITEM_REFERENCE private class ItemReference { internal ItemReference(object item) { _item = item; } internal object Item { get { return _item; } } object _item; } #endif // change WeakDependencySources to (strong) DependencySources, and notify // the property engine about the new sources void ChangeSources(DependencyObject target, DependencyProperty dp, WeakDependencySource[] newSources) { DependencySource[] sources; if (newSources != null) { // convert weak reference to strong sources = new DependencySource[newSources.Length]; int n = 0; for (int i = 0; i < newSources.Length; ++i) { DependencyObject sourceDO = newSources[i].DependencyObject; if (sourceDO != null) { // only include sources that are still alive sources[n++] = new DependencySource(sourceDO, newSources[i].DependencyProperty); } } // if any of the sources were no longer alive, trim the array if (n < newSources.Length) { DependencySource[] temp; if (n > 0) { temp = new DependencySource[n]; Array.Copy(sources, 0, temp, 0, n); } else { temp = null; } sources = temp; } } else { sources = null; } // notify property engine ChangeSources(target, dp, sources); } // this method is here just to avoid the compiler error // error CS0649: Warning as Error: Field 'System.Windows.Data.BindingExpression._traceLog' is never assigned to, and will always have its default value null void InitializeTraceLog() { _traceLog = new TraceLog(20); } //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- BindingBase _binding; WeakReference _targetElement; DependencyProperty _targetProperty; DataBindEngine _engine; PrivateFlags _flags; BindingExpressionBase _parentBindingExpression; object _value = DefaultValueObject; BindingStatus _status; TraceLog _traceLog; ValidationError _validationError; WeakDependencySource[] _sources; object _culture = DefaultValueObject; /// Sentinel meaning "field has its default value" internal static readonly object DefaultValueObject = new object(); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsSolidBrush.cs
- IProvider.cs
- ReflectionUtil.cs
- PromptBuilder.cs
- Geometry.cs
- SapiInterop.cs
- TemplateComponentConnector.cs
- CalendarDateChangedEventArgs.cs
- Camera.cs
- ChangeProcessor.cs
- SamlAuthorizationDecisionClaimResource.cs
- ToolStripGripRenderEventArgs.cs
- PersonalizationStateInfoCollection.cs
- ServiceControllerDesigner.cs
- JsonWriter.cs
- Operand.cs
- AppSettingsSection.cs
- StandardBindingElement.cs
- EventManager.cs
- SqlCacheDependencyDatabase.cs
- Types.cs
- PointCollection.cs
- ActivityDesignerLayoutSerializers.cs
- SafePEFileHandle.cs
- _CookieModule.cs
- MailDefinitionBodyFileNameEditor.cs
- ToolStripRenderer.cs
- AssociationEndMember.cs
- TdsParserSafeHandles.cs
- DifferencingCollection.cs
- HtmlInputCheckBox.cs
- XmlLinkedNode.cs
- JsonEnumDataContract.cs
- ConfigXmlText.cs
- PathNode.cs
- ApplicationSettingsBase.cs
- Binding.cs
- SqlClientWrapperSmiStreamChars.cs
- DesignerSerializationOptionsAttribute.cs
- TextBoxRenderer.cs
- CapacityStreamGeometryContext.cs
- FixedSOMTable.cs
- LineVisual.cs
- SiteMembershipCondition.cs
- CompressedStack.cs
- ClusterUtils.cs
- TreeWalker.cs
- PermissionSetTriple.cs
- SynchronizationContext.cs
- CodeAccessPermission.cs
- IListConverters.cs
- HtmlTableCell.cs
- EntityReference.cs
- compensatingcollection.cs
- MouseActionConverter.cs
- WsdlBuildProvider.cs
- Int64KeyFrameCollection.cs
- HttpCapabilitiesBase.cs
- QuaternionValueSerializer.cs
- dsa.cs
- MustUnderstandSoapException.cs
- TableProviderWrapper.cs
- _AcceptOverlappedAsyncResult.cs
- ArrayWithOffset.cs
- XmlCompatibilityReader.cs
- TextTreeInsertUndoUnit.cs
- ToolStripContentPanelRenderEventArgs.cs
- SpnegoTokenProvider.cs
- GrammarBuilderRuleRef.cs
- QilNode.cs
- IsolatedStorageFilePermission.cs
- XmlFormatExtensionPointAttribute.cs
- NameTable.cs
- SafeCryptHandles.cs
- UserValidatedEventArgs.cs
- xml.cs
- WindowsTitleBar.cs
- InvalidWMPVersionException.cs
- WmlPageAdapter.cs
- WindowPatternIdentifiers.cs
- BufferAllocator.cs
- Transform3DGroup.cs
- UnlockInstanceCommand.cs
- GenerateScriptTypeAttribute.cs
- StaticSiteMapProvider.cs
- HtmlShimManager.cs
- DataListItemEventArgs.cs
- DataGridDetailsPresenter.cs
- SqlErrorCollection.cs
- TypeGeneratedEventArgs.cs
- ToolStripItemClickedEventArgs.cs
- GuidelineCollection.cs
- Rule.cs
- LogManagementAsyncResult.cs
- JsonSerializer.cs
- TreeNodeBinding.cs
- TdsRecordBufferSetter.cs
- StylusPoint.cs
- DataGridViewComboBoxEditingControl.cs
- RowTypePropertyElement.cs