ResourceReferenceExpression.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 / ResourceReferenceExpression.cs / 1 / ResourceReferenceExpression.cs

                            //---------------------------------------------------------------------------- 
//
// File: ResourceReferenceExpression.cs
//
// Description: 
//   Expression to evaluate a ResourceReference.
// 
// Copyright (C) 2003 by Microsoft Corporation.  All rights reserved. 
//
//--------------------------------------------------------------------------- 

using System;
using System.ComponentModel;
using System.Diagnostics; 
using System.Windows.Markup;
using MS.Internal; 
 
namespace System.Windows
{ 
    /// 
    ///     Expression to evaluate a ResourceReference
    /// 
    [TypeConverter(typeof(ResourceReferenceExpressionConverter))] 
    internal class ResourceReferenceExpression : Expression
    { 
        ///  
        ///     Constructor for ResourceReferenceExpression
        ///  
        /// 
        ///     Name of the resource being referenced
        /// 
        public ResourceReferenceExpression(object resourceKey) 
        {
            _resourceKey = resourceKey; 
        } 

        ///  
        ///     List of sources of the ResourceReferenceExpression
        /// 
        /// Sources list
        internal override DependencySource[] GetSources() 
        {
            return null; 
        } 

        ///  
        ///     Called to evaluate the ResourceReferenceExpression value
        /// 
        /// DependencyObject being queried
        /// Property being queried 
        /// Computed value. Unset if unavailable.
        internal override object GetValue(DependencyObject d, DependencyProperty dp) 
        { 
            if (d == null)
            { 
                throw new ArgumentNullException("d");
            }
            if (dp == null)
            { 
                throw new ArgumentNullException("dp");
            } 
 
            // If the cached value is valid then return it
            if (ReadInternalState(InternalState.HasCachedResourceValue) == true) 
                return _cachedResourceValue;

            object source;
            return GetRawValue(d, out source, dp); 
        }
 
 
        // Clone a copy of this expression (this is used by Freezable.Copy)
        internal override Expression Copy( DependencyObject targetObject, DependencyProperty targetDP ) 
        {
            return new ResourceReferenceExpression( ResourceKey );
        }
 

        ///  
        ///     Called to evaluate the ResourceReferenceExpression value 
        /// 
        /// DependencyObject being queried 
        /// Source object that the resource is found on
        /// DependencyProperty
        /// Computed value. Unset if unavailable.
        ///  
        /// This routine has been separated from the above GetValue call because it is
        /// invoked by the ResourceReferenceExpressionConverter during serialization. 
        ///  
        internal object GetRawValue(DependencyObject d, out object source, DependencyProperty dp)
        { 
            // Find the mentor node to invoke FindResource on. For example
            //  
        ///     Allows ResourceReferenceExpression to store set values 
        /// 
        /// DependencyObject being set 
        /// Property being set
        /// Value being set
        /// true if ResourceReferenceExpression handled storing of the value
        internal override bool SetValue(DependencyObject d, DependencyProperty dp, object value) 
        {
            return false; 
        } 

        ///  
        ///     Notification that the ResourceReferenceExpression has been set as a property's value
        /// 
        /// DependencyObject being set
        /// Property being set 
        internal override void OnAttach(DependencyObject d, DependencyProperty dp)
        { 
            _targetObject = d; 
            _targetProperty = dp;
 
            FrameworkObject fo = new FrameworkObject(_targetObject);

            fo.HasResourceReference = true;
 
            if (!fo.IsValid)
            { 
                // Listen for the InheritanceContextChanged event on the target node, 
                // so that if this context hierarchy changes we can re-evaluate this expression.
                _targetObject.InheritanceContextChanged += new EventHandler(InvalidateExpressionValue); 
            }
        }

        ///  
        ///     Notification that the ResourceReferenceExpression has been removed as a property's value
        ///  
        /// DependencyObject being cleared 
        /// Property being cleared
        internal override void OnDetach(DependencyObject d, DependencyProperty dp) 
        {
            // Invalidate all the caches
            InvalidateMentorCache();
 
            if (!(_targetObject is FrameworkElement) && !(_targetObject is FrameworkContentElement))
            { 
                // Stop listening for the InheritanceContextChanged event on the target node 
                _targetObject.InheritanceContextChanged -= new EventHandler(InvalidateExpressionValue);
            } 

            _targetObject = null;
            _targetProperty = null;
        } 

        ///  
        ///     Key used to lookup the resource 
        /// 
        public object ResourceKey 
        {
            get { return _resourceKey; }
        }
 
        /// 
        /// This method is called when the cached value of the resource has 
        /// been invalidated.  E.g. after a new Resources property is set somewhere 
        /// in the ancestory.
        ///  
        private void InvalidateCacheValue()
        {
            object resource = _cachedResourceValue;
 
            // If the old value was a DeferredResourceReference, it should be
            // removed from its Dictionary's list to avoid a leak (bug 1624666). 
            DeferredResourceReference deferredResourceReference = _cachedResourceValue as DeferredResourceReference; 
            if (deferredResourceReference != null)
            { 
                if (deferredResourceReference.IsInflated)
                {
                    // use the inflated value for the Freezable test below
                    resource = deferredResourceReference.Value; 
                }
                else 
                { 
                    // stop listening for the Inflated event
                    if (ReadInternalState(InternalState.IsListeningForInflated)) 
                    {
                        deferredResourceReference.Inflated -= new EventHandler(OnDeferredResourceInflated);
                        WriteInternalState(InternalState.IsListeningForInflated, false);
                    } 
                }
 
                deferredResourceReference.RemoveFromDictionary(); 
            }
 
            StopListeningForFreezableChanges(resource);

            _cachedResourceValue = null;
            WriteInternalState(InternalState.HasCachedResourceValue, false); 
        }
 
        ///  
        ///     This method is called to invalidate all the cached values held in
        ///     this expression. This is called under the following 3 scenarios 
        ///     1. InheritanceContext changes
        ///     2. Logical tree changes
        ///     3. ResourceDictionary changes
        ///     This call is more pervasive than the InvalidateCacheValue method 
        /// 
        private void InvalidateMentorCache() 
        { 
            if (ReadInternalState(InternalState.IsMentorCacheValid) == true)
            { 
                if (_mentorCache != null)
                {
                    if (_mentorCache != _targetObject)
                    { 
                        FrameworkElement mentorFE;
                        FrameworkContentElement mentorFCE; 
                        Helper.DowncastToFEorFCE(_mentorCache, out mentorFE, out mentorFCE, true); 

                        // Your mentor is about to change, make sure you detach handlers for 
                        // the events that you were listening on the old mentor
                        if (mentorFE != null)
                        {
                            mentorFE.ResourcesChanged -= new EventHandler(InvalidateExpressionValue); 
                        }
                        else 
                        { 
                            mentorFCE.ResourcesChanged -= new EventHandler(InvalidateExpressionValue);
                        } 
                    }

                    // Drop the mentor cache
                    _mentorCache = null; 
                }
 
                // Mark the cache invalid 
                WriteInternalState(InternalState.IsMentorCacheValid, false);
            } 

            // Invalidate the cached value of the expression
            InvalidateCacheValue();
        } 

        ///  
        ///     This event handler is called to invalidate the cached value held in 
        ///     this expression. This is called under the following 3 scenarios
        ///     1. InheritanceContext changes 
        ///     2. Logical tree changes
        ///     3. ResourceDictionary changes
        /// 
        internal void InvalidateExpressionValue(object sender, EventArgs e) 
        {
            ResourcesChangedEventArgs args = e as ResourcesChangedEventArgs; 
            if (args != null) 
            {
                ResourcesChangeInfo info = args.Info; 
                if (!info.IsTreeChange)
                {
                    // This will happen when
                    // 1. Theme changes 
                    // 2. Entire ResourceDictionary in the ancestry changes
                    // 3. Single entry in a ResourceDictionary in the ancestry is changed 
                    // In all of the above cases it is sufficient to re-evaluate the cache 
                    // value alone. The mentor relation ships stay the same.
                    InvalidateCacheValue(); 
                }
                else
                {
                    // This is the case of a logical tree change and hence we need to 
                    // re-evaluate both the mentor and the cached value.
                    InvalidateMentorCache(); 
                } 
            }
            else 
            {
                // There is no information provided by the EventArgs. Hence we
                // pessimistically invalidate both the mentor and the cached value.
                // This code path will execute when the InheritanceContext changes. 
                InvalidateMentorCache();
            } 
 
            InvalidateTargetProperty(sender, e);
        } 

        private void InvalidateTargetProperty(object sender, EventArgs e)
        {
            _targetObject.InvalidateProperty(_targetProperty); 
        }
 
        private void InvalidateTargetSubProperty(object sender, EventArgs e) 
        {
            _targetObject.NotifySubPropertyChange(_targetProperty); 
        }

        private void ListenForFreezableChanges(object resource)
        { 
            if (!ReadInternalState(InternalState.IsListeningForFreezableChanges))
            { 
                // If this value is an unfrozen Freezable object, we need 
                //  to listen to its changed event in order to properly update
                //  the cache. 
                Freezable resourceAsFreezable = resource as Freezable;
                if( resourceAsFreezable != null && !resourceAsFreezable.IsFrozen )
                {
                    resourceAsFreezable.Changed += new EventHandler(InvalidateTargetSubProperty); 
                    WriteInternalState(InternalState.IsListeningForFreezableChanges, true);
                } 
            } 
        }
 
        private void StopListeningForFreezableChanges(object resource)
        {
            if (ReadInternalState(InternalState.IsListeningForFreezableChanges))
            { 
                // If the old value was an unfrozen Freezable object, we need
                //  to stop listening to its changed event.  If the old value wasn't 
                //  frozen (hence we attached an listener) but has been frozen 
                //  since then, the change handler we had attached was already
                //  discarded during the freeze so we don't care here. 
                Freezable resourceAsFreezable = resource as Freezable;
                if( resourceAsFreezable != null && !resourceAsFreezable.IsFrozen )
                {
                    resourceAsFreezable.Changed -= new EventHandler(InvalidateTargetSubProperty); 
                    WriteInternalState(InternalState.IsListeningForFreezableChanges, false);
                } 
            } 
        }
 
        // when a deferred resource reference is inflated, the value may need extra
        // work
        private void OnDeferredResourceInflated(object sender, EventArgs e)
        { 
            DeferredResourceReference deferredResourceReference = (DeferredResourceReference)sender;
 
            // once the value is inflated, stop listening for the event 
            deferredResourceReference.Inflated -= new EventHandler(OnDeferredResourceInflated);
            WriteInternalState(InternalState.IsListeningForInflated, false); 

            ListenForFreezableChanges(deferredResourceReference.Value);
        }
 
        // Extracts the required flag and returns
        // bool to indicate if it is set or unset 
        private bool ReadInternalState(InternalState reqFlag) 
        {
            return (_state & reqFlag) != 0; 
        }

        // Sets or Unsets the required flag based on
        // the bool argument 
        private void WriteInternalState(InternalState reqFlag, bool set)
        { 
            if (set) 
            {
                _state |= reqFlag; 
            }
            else
            {
                _state &= (~reqFlag); 
            }
        } 
 
        private object _resourceKey; // Name of the resource being referenced by this expression
 
        // Cached value and a dirty bit.  See GetValue.
        private object _cachedResourceValue;

        // Used to find the value for this expression when it is set on a non-FE/FCE. 
        // The mentor is the FE/FCE that the FindResource method is invoked on.
        private DependencyObject _mentorCache; 
 
        // Used by the change listener to fire invalidation.
        private DependencyObject _targetObject; 
        private DependencyProperty _targetProperty;

        // Bit Fields used to store boolean flags
        private InternalState _state = InternalState.Default;  // this is a byte (see def'n) 

        ///  
        /// This enum represents the internal state of the RRE. 
        /// Additional bools should be coalesced into this enum.
        ///  
        [Flags]
        private enum InternalState : byte
        {
            Default                       = 0x00, 
            HasCachedResourceValue        = 0x01,
            IsMentorCacheValid            = 0x02, 
            DisableThrowOnResourceFailure = 0x04, 
            IsListeningForFreezableChanges= 0x08,
            IsListeningForInflated        = 0x10, 
        }
    }

    ///  
    ///     These EventArgs are used to pass additional
    ///     information during a ResourcesChanged event 
    ///  
    internal class ResourcesChangedEventArgs : EventArgs
    { 
        internal ResourcesChangedEventArgs(ResourcesChangeInfo info)
        {
            _info = info;
        } 

        internal ResourcesChangeInfo Info 
        { 
            get { return _info; }
        } 

        private ResourcesChangeInfo _info;
    }
} 


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