Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Style.cs / 1 / Style.cs
/****************************************************************************\ * * File: Style.cs * * Style and templating. * * Copyright (C) 2003 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; // For Debug.Assert using System.Windows.Threading; using System.Threading; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Animation; // For Storyboard support using System.Windows.Markup; using System.Security.Permissions; using System.IO; using MS.Utility; using MS.Internal; using System; #pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows { ////// Styling and Templating /// [Localizability(LocalizationCategory.Ignore)] [ContentProperty("Setters")] public class Style : DispatcherObject, INameScope, IAddChild, ISealable, IHaveResources { static Style() { // Register for the "alternative Expression storage" feature, since // we store Expressions in per-instance StyleData. StyleHelper.RegisterAlternateExpressionStorage(); } ////// Style construction /// public Style() { GetUniqueGlobalIndex(); } ////// Style construction /// /// Type in which Style will be applied public Style(Type targetType) { TargetType = targetType; GetUniqueGlobalIndex(); } ////// Style construction /// /// Type in which Style will be applied /// Style to base this Style on public Style(Type targetType, Style basedOn) { TargetType = targetType; BasedOn = basedOn; GetUniqueGlobalIndex(); } #region INameScope ////// Registers the name - Context combination /// /// Name to register /// Element where name is defined public void RegisterName(string name, object scopedElement) { // Verify Context Access VerifyAccess(); _nameScope.RegisterName(name, scopedElement); } ////// Unregisters the name - element combination /// /// Name of the element public void UnregisterName(string name) { // Verify Context Access VerifyAccess(); _nameScope.UnregisterName(name); } ////// Find the element given name /// /// Name of the element object INameScope.FindName(string name) { // Verify Context Access VerifyAccess(); return _nameScope.FindName(name); } private NameScope _nameScope = new NameScope(); #endregion IIdScope ////// Each Style gets its own unique index used for Style.GetHashCode /// private void GetUniqueGlobalIndex() { lock (Synchronized) { // Setup unqiue global index StyleInstanceCount++; GlobalIndex = StyleInstanceCount; } } ////// Style mutability state /// ////// A style is sealed when another style is basing on it, or, /// when it's applied /// public bool IsSealed { get { // Verify Context Access VerifyAccess(); return _sealed; } } ////// Type that this style is intended /// ////// By default, the target type is FrameworkElement /// [Localizability(LocalizationCategory.NeverLocalize)] public Type TargetType { get { // Verify Context Access VerifyAccess(); return _targetType; } set { // Verify Context Access VerifyAccess(); if (_sealed) { throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "Style")); } if( value == null ) { throw new ArgumentNullException("value"); } if (!typeof(FrameworkElement).IsAssignableFrom(value) && !typeof(FrameworkContentElement).IsAssignableFrom(value) && !(DefaultTargetType == value)) { #pragma warning suppress 6506 // value is obviously not null throw new ArgumentException(SR.Get(SRID.MustBeFrameworkDerived, value.Name)); } _targetType = value; SetModified(TargetTypeID); } } ////// Style to base on /// [DefaultValue(null)] public Style BasedOn { get { // Verify Context Access VerifyAccess(); return _basedOn; } set { // Verify Context Access VerifyAccess(); if (_sealed) { throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "Style")); } if( value == this ) { // Basing on self is not allowed. This is a degenerate case // of circular reference chain, the full check for circular // reference is done in Seal(). throw new ArgumentException(SR.Get(SRID.StyleCannotBeBasedOnSelf)); } _basedOn = value; SetModified(BasedOnID); } } ////// Visual triggers /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public TriggerCollection Triggers { get { // Verify Context Access VerifyAccess(); if (_visualTriggers == null) { _visualTriggers = new TriggerCollection(); // If the style has been sealed prior to this the newly // created TriggerCollection also needs to be sealed if (_sealed) { _visualTriggers.Seal(); } } return _visualTriggers; } } ////// The collection of property setters for the target type /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public SetterBaseCollection Setters { get { // Verify Context Access VerifyAccess(); if( _setters == null ) { _setters = new SetterBaseCollection(); // If the style has been sealed prior to this the newly // created SetterBaseCollection also needs to be sealed if (_sealed) { _setters.Seal(); } } return _setters; } } ////// The collection of resources that can be /// consumed by the container and its sub-tree. /// public ResourceDictionary Resources { get { // Verify Context Access VerifyAccess(); if( _resources == null ) { _resources = new ResourceDictionary(); // A Style ResourceDictionary can be accessed across threads _resources.CanBeAccessedAcrossThreads = true; // If the style has been sealed prior to this the newly // created ResourceDictionary also needs to be sealed if (_sealed) { _resources.IsReadOnly = true; } } return _resources; } set { // Verify Context Access VerifyAccess(); if( _sealed ) { throw new InvalidOperationException(SR.Get(SRID.CannotChangeAfterSealed, "Style")); } _resources = value; if (_resources != null) { // A Style ResourceDictionary can be accessed across threads _resources.CanBeAccessedAcrossThreads = true; } } } ResourceDictionary IHaveResources.Resources { get { return Resources; } set { Resources = value; } } ////// Tries to find a Reosurce for the given resourceKey in the current /// style's ResourceDictionary or the basedOn style's ResourceDictionary /// in that order. /// internal object FindResource(object resourceKey, bool allowDeferredResourceReference, bool mustReturnDeferredResourceReference) { if ((_resources != null) && _resources.Contains(resourceKey)) { bool canCache; return _resources.FetchResource(resourceKey, allowDeferredResourceReference, mustReturnDeferredResourceReference, out canCache); } if (_basedOn != null) { return _basedOn.FindResource(resourceKey, allowDeferredResourceReference, mustReturnDeferredResourceReference); } return DependencyProperty.UnsetValue; } ////// This method is called to Add a Setter object as a child of the Style. /// This method is used primarily by the parser to set style properties and events. /// /// /// The object to add as a child; it must be a SetterBase subclass. /// void IAddChild.AddChild (Object value) { // Verify Context Access VerifyAccess(); if (value == null) { throw new ArgumentNullException("value"); } SetterBase sb = value as SetterBase; if (sb == null) { throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(SetterBase)), "value"); } Setters.Add(sb); } ////// This method is called by the parser when text appears under the tag in markup. /// As default Styles do not support text, calling this method has no effect. /// /// /// Text to add as a child. /// void IAddChild.AddText (string text) { // Verify Context Access VerifyAccess(); XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this); } ////// Given a set of values for the PropertyValue struct, put that in /// to the PropertyValueList, overwriting any existing entry. /// private void UpdatePropertyValueList( DependencyProperty dp, PropertyValueType valueType, object value) { // Check for existing value on dp int existingIndex = -1; for( int i = 0; i < PropertyValues.Count; i++ ) { if( PropertyValues[i].Property == dp ) { existingIndex = i; break; } } if( existingIndex >= 0 ) { // Overwrite existing value for dp PropertyValue propertyValue = PropertyValues[existingIndex]; propertyValue.ValueType = valueType; propertyValue.ValueInternal = value; // Put back modified struct PropertyValues[existingIndex] = propertyValue; } else { // Store original data PropertyValue propertyValue = new PropertyValue(); propertyValue.ValueType = valueType; propertyValue.ChildName = StyleHelper.SelfName; propertyValue.Property = dp; propertyValue.ValueInternal = value; PropertyValues.Add(propertyValue); } } internal void CheckTargetType(object element) { // In the most common case TargetType is Default // and we can avoid a call to IsAssignableFrom() who's performance is unknown. if(DefaultTargetType == TargetType) return; Type elementType = element.GetType(); if(!TargetType.IsAssignableFrom(elementType)) { throw new InvalidOperationException(SR.Get(SRID.StyleTargetTypeMismatchWithElement, this.TargetType.Name, elementType.Name)); } } ////// This Style and all factories/triggers are now immutable /// public void Seal() { // Verify Context Access VerifyAccess(); // 99% case - Style is already sealed. if (_sealed) { return; } // Most parameter checking is done as "upstream" as possible, but some // can't be checked until Style is sealed. if (_targetType == null) { throw new InvalidOperationException(SR.Get(SRID.NullPropertyIllegal, "TargetType")); } if (_basedOn != null) { if(DefaultTargetType != _basedOn.TargetType && !_basedOn.TargetType.IsAssignableFrom(_targetType)) { throw new InvalidOperationException(SR.Get(SRID.MustBaseOnStyleOfABaseType, _targetType.Name)); } } // Seal setters if (_setters != null) { _setters.Seal(); } // Seal triggers if (_visualTriggers != null) { _visualTriggers.Seal(); } // Will throw InvalidOperationException if we find a loop of // BasedOn references. (A.BasedOn = B, B.BasedOn = C, C.BasedOn = A) CheckForCircularBasedOnReferences(); // Seal BasedOn Style chain if (_basedOn != null) { _basedOn.Seal(); } // Seal the ResourceDictionary if (_resources != null) { _resources.IsReadOnly = true; } // // Build shared tables // // Process all Setters set on the selfStyle. This stores all the property // setters on the current styles into PropertyValues list, so it can be used // by ProcessSelfStyle in the next step. The EventSetters for the current // and all the basedOn styles are merged into the EventHandlersStore on the // current style. ProcessSetters(this); // Add an entry in the EventDependents list for // the TargetType's EventHandlersStore. Notice // that the childIndex is 0. StyleHelper.AddEventDependent(0, this.EventHandlersStore, ref EventDependents); // Process all PropertyValues (all are "Self") in the Style // chain (base added first) ProcessSelfStyles(this); // Process all TriggerBase PropertyValues ("Self" triggers // and child triggers) in the Style chain last (highest priority) ProcessVisualTriggers(this); // Sort the ResourceDependents, to help avoid duplicate invalidations StyleHelper.SortResourceDependents(ref ResourceDependents); // All done, seal self and call it a day. _sealed = true; // Remove thread affinity so it can be accessed across threads DetachFromDispatcher(); } ////// This method checks to see if the BasedOn hierarchy contains /// a loop in the chain of references. /// ////// Classic "when did we enter the cycle" problem where we don't know /// what to start remembering and what to check against. Brute- /// force approach here is to remember everything with a stack /// and do a linear comparison through everything. Since the Style /// BasedOn hierarchy is not expected to be large, this should be OK. /// private void CheckForCircularBasedOnReferences() { Stack basedOnHierarchy = new Stack(10); // 10 because that's the default value (see MSDN) and the perf team wants us to specify something. Style latestBasedOn = this; while( latestBasedOn != null ) { if( basedOnHierarchy.Contains( latestBasedOn ) ) { // Uh-oh. We've seen this Style before. This means // the BasedOn hierarchy contains a loop. throw new InvalidOperationException(SR.Get( SRID.StyleBasedOnHasLoop)); // Debugging note: If we stop here, the basedOnHierarchy // object is still alive and we can browse through it to // see what we've explored. (This does not apply if // somebody catches this exception and re-throws.) } // Haven't seen it, push on stack and go to next level. basedOnHierarchy.Push( latestBasedOn ); latestBasedOn = latestBasedOn.BasedOn; } return; } // Iterates through the setters collection and adds the EventSetter information into // an EventHandlersStore for easy and fast retrieval during event routing. Also adds // an entry in the EventDependents list for EventhandlersStore holding the TargetType's // events. private void ProcessSetters(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } style.Setters.Seal(); // Does not mark individual setters as sealed, that's up to the loop below. // On-demand create the PropertyValues list, so that we can specify the right size. if(PropertyValues.Count == 0) { PropertyValues = new FrugalStructList(style.Setters.Count); } // Add EventSetters to local EventHandlersStore for (int i = 0; i < style.Setters.Count; i++) { SetterBase setterBase = style.Setters[i]; Debug.Assert(setterBase != null, "Setter collection must contain non-null instances of SetterBase"); // Setters are folded into the PropertyValues table only for the current style. The // processing of BasedOn Style properties will occur in subsequent call to ProcessSelfStyle Setter setter = setterBase as Setter; if (setter != null) { // Style Setters are not allowed to have a child target name - since there are no child nodes in a Style. if( setter.TargetName != null ) { throw new InvalidOperationException(SR.Get(SRID.SetterOnStyleNotAllowedToHaveTarget, setter.TargetName)); } if (style == this) { DynamicResourceExtension dynamicResource = setter.ValueInternal as DynamicResourceExtension; if (dynamicResource == null) { UpdatePropertyValueList( setter.Property, PropertyValueType.Set, setter.ValueInternal ); } else { UpdatePropertyValueList( setter.Property, PropertyValueType.Resource, dynamicResource.ResourceKey ); } } } else { Debug.Assert(setterBase is EventSetter, "Unsupported SetterBase subclass in style triggers ({0})", setterBase.GetType().ToString()); // Add this to the _eventHandlersStore EventSetter eventSetter = (EventSetter)setterBase; if (_eventHandlersStore == null) { _eventHandlersStore = new EventHandlersStore(); } _eventHandlersStore.AddRoutedEventHandler(eventSetter.Event, eventSetter.Handler, eventSetter.HandledEventsToo); SetModified(HasEventSetter); // If this event setter watches the loaded/unloaded events, set the optimization // flag. if (eventSetter.Event == FrameworkElement.LoadedEvent || eventSetter.Event == FrameworkElement.UnloadedEvent) { _hasLoadedChangeHandler = true; } } } // Process EventSetters on based on style so they get merged // into the EventHandlersStore for the current style. ProcessSetters(style._basedOn); } private void ProcessSelfStyles(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } ProcessSelfStyles(style._basedOn); // Merge in "self" PropertyValues while walking back up the tree // "Based-on" style "self" rules are always added first (lower priority) for (int i = 0; i < style.PropertyValues.Count; i++) { PropertyValue propertyValue = style.PropertyValues[i]; StyleHelper.UpdateTables(ref propertyValue, ref ChildRecordFromChildIndex, ref TriggerSourceRecordFromChildIndex, ref ResourceDependents, ref _dataTriggerRecordFromBinding, null /*_childIndexFromChildID*/, ref _hasInstanceValues); // Track properties on the container that are being driven by // the Style so that they can be invalidated during style changes StyleHelper.AddContainerDependent(propertyValue.Property, false /*fromVisualTrigger*/, ref ContainerDependents); } } private void ProcessVisualTriggers(Style style) { // Walk down to bottom of based-on chain if (style == null) { return; } ProcessVisualTriggers(style._basedOn); if (style._visualTriggers != null) { // Merge in "self" and child TriggerBase PropertyValues while walking // back up the tree. "Based-on" style rules are always added first // (lower priority) int triggerCount = style._visualTriggers.Count; for (int i = 0; i < triggerCount; i++) { TriggerBase trigger = style._visualTriggers[i]; // Set things up to handle Setter values for (int j = 0; j < trigger.PropertyValues.Count; j++) { PropertyValue propertyValue = trigger.PropertyValues[j]; // Check for trigger rules that act on container if (propertyValue.ChildName != StyleHelper.SelfName) { throw new InvalidOperationException(SR.Get(SRID.StyleTriggersCannotTargetTheTemplate)); } TriggerCondition[] conditions = propertyValue.Conditions; for (int k=0; k 0 ) { throw new InvalidOperationException(SR.Get(SRID.EventTriggerOnStyleNotAllowedToHaveTarget, eventTrigger.SourceName)); } StyleHelper.ProcessEventTrigger(eventTrigger, null /*_childIndexFromChildID*/, ref _triggerActions, ref EventDependents, null /*_templateFactoryRoot*/, null, ref _eventHandlersStore, ref _hasLoadedChangeHandler); } } } } /// /// Serves as a hash function for a particular type, suitable for use in /// hashing algorithms and data structures like a hash table /// ///The Style's GlobalIndex public override int GetHashCode() { // Verify Context Access VerifyAccess(); return GlobalIndex; } #region ISealable ////// Can this style be sealed /// bool ISealable.CanSeal { get { return true; } } ////// Is this style sealed /// bool ISealable.IsSealed { get { return IsSealed; } } ////// Seal this style /// void ISealable.Seal() { Seal(); } #endregion ISealable internal bool HasResourceReferences { get { return ResourceDependents.Count > 0; } } ////// Store all the event handlers for this Style TargetType /// internal EventHandlersStore EventHandlersStore { get { return _eventHandlersStore; } } ////// Does the current style or any of its template children /// have any event setters OR event triggers /// internal bool HasEventDependents { get { return (EventDependents.Count > 0); } } ////// Does the current style or any of its template children /// have event setters, ignoring event triggers. /// internal bool HasEventSetters { get { return IsModified(HasEventSetter); } } // // Says if this style contains any per-instance values // internal bool HasInstanceValues { get { return _hasInstanceValues; } } // // Says if we have anything listening for the Loaded or Unloaded // event (used for an optimization in FrameworkElement). // internal bool HasLoadedChangeHandler { get { return _hasLoadedChangeHandler; } set { _hasLoadedChangeHandler = value; } } // Special equality check that takes into account 'null' private static bool IsEqual(object a, object b) { return (a != null) ? a.Equals(b) : (b == null); } internal bool IsBasedOnModified { get { return IsModified(BasedOnID); } } private EventHandlersStore _eventHandlersStore = null; private bool _sealed; private bool _hasInstanceValues; internal static readonly Type DefaultTargetType = typeof(IFrameworkInputElement); private bool _hasLoadedChangeHandler; private Type _targetType = DefaultTargetType; private Style _basedOn; private TriggerCollection _visualTriggers = null; private SetterBaseCollection _setters = null; // Holds resources that are applicable to the container // of this style and its sub-tree. internal ResourceDictionary _resources = null; /* property */ internal int GlobalIndex; // Style tables // Synchronized (write locks, lock-free reads): Covered by Style instance lock /* property */ internal FrugalStructListChildRecordFromChildIndex = new FrugalStructList (); // Indexed by Child.ChildIndex // Synchronized (write locks, lock-free reads): Covered by Style instance lock // // Shared tables used during OnTriggerSourcePropertyInvalidated // internal FrugalStructList > TriggerSourceRecordFromChildIndex = new FrugalStructList >(); // Dictionary of property triggers that have TriggerActions, keyed via DP.GlobalIndex affecting those triggers. // Each trigger can be listed multiple times, if they are dependent on multiple properties. internal FrugalMap PropertyTriggersWithActions; // Original Style data (not including based-on data) // Synchronized (write locks, lock-free reads): Covered by Style instance lock /* property */ internal FrugalStructList PropertyValues = new FrugalStructList (); // Properties driven on the container (by the Style) that should be // invalidated when the style gets applied/unapplied. These properties // could have been set via Style.SetValue or TriggerBase.SetValue // Synchronized (write locks, lock-free reads): Covered by Style instance lock /* property */ internal FrugalStructList ContainerDependents = new FrugalStructList (); // Properties driven by a resource that should be invalidated // when a resource dictionary changes // Synchronized (write locks, lock-free reads): Covered by Style instance lock /* property */ internal FrugalStructList ResourceDependents = new FrugalStructList (); // Events driven by a this style. An entry for every childIndex that has associated events. // childIndex '0' is used to represent events set on the style's TargetType. This data-structure // will be frequently looked up during event routing. // Synchronized (write locks, lock-free reads): Covered by Style instance lock /* property */ internal ItemStructList EventDependents = new ItemStructList (1); // Used by EventTrigger: Maps a RoutedEventID to a set of TriggerAction objects // to be performed. internal HybridDictionary _triggerActions = null; // Data trigger information. An entry for each Binding that appears in a // condition of a data trigger. // Synchronized: Covered by Style instance internal HybridDictionary _dataTriggerRecordFromBinding; // An entry for each Binding that appears in a DataTrigger with EnterAction or ExitAction // This overlaps but should not be the same as _dataTriggerRecordFromBinding above: // A DataTrigger can have Setters but no EnterAction/ExitAction. (The reverse can also be true.) internal HybridDictionary DataTriggersWithActions = null; // Unique index for every instance of Style // Synchronized: Covered by Style.Synchronized private static int StyleInstanceCount = 0; // Global, cross-object synchronization internal static object Synchronized = new object(); private const int TargetTypeID = 0x01; internal const int BasedOnID = 0x02; // Using the modified flags to note whether we have an EventSetter. private const int HasEventSetter = 0x10; private int _modified = 0; private void SetModified(int id) { _modified |= id; } internal bool IsModified(int id) { return (id & _modified) != 0; } } } // 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
- IndividualDeviceConfig.cs
- UriSectionData.cs
- Rotation3DAnimationBase.cs
- Condition.cs
- XmlSchemaRedefine.cs
- NamespaceList.cs
- CompilationPass2TaskInternal.cs
- ReadOnlyDataSource.cs
- SpecialNameAttribute.cs
- Dictionary.cs
- AssertHelper.cs
- CodeRemoveEventStatement.cs
- EdmToObjectNamespaceMap.cs
- SQLInt16.cs
- ScriptBehaviorDescriptor.cs
- TemplateBindingExpression.cs
- ByteRangeDownloader.cs
- MimeFormReflector.cs
- ListViewAutomationPeer.cs
- Verify.cs
- webproxy.cs
- WebPartConnectionsConfigureVerb.cs
- HiddenField.cs
- SegmentInfo.cs
- RSACryptoServiceProvider.cs
- Debug.cs
- HttpRequest.cs
- SqlDataRecord.cs
- WebPartMenu.cs
- DateTimeUtil.cs
- DataBoundControlActionList.cs
- StaticFileHandler.cs
- XmlNodeComparer.cs
- AccessorTable.cs
- StateMachineHistory.cs
- ModelTypeConverter.cs
- ProcessHostFactoryHelper.cs
- OpacityConverter.cs
- EntryWrittenEventArgs.cs
- GridViewRow.cs
- XmlParserContext.cs
- LinkClickEvent.cs
- NavigateEvent.cs
- mactripleDES.cs
- CodePageUtils.cs
- XmlEntity.cs
- UserControlAutomationPeer.cs
- QueueProcessor.cs
- TableItemProviderWrapper.cs
- QilCloneVisitor.cs
- StatusBar.cs
- CombinedGeometry.cs
- SerializerDescriptor.cs
- PartialTrustVisibleAssembly.cs
- ContainerParaClient.cs
- PageBreakRecord.cs
- TextCompositionManager.cs
- BevelBitmapEffect.cs
- InProcStateClientManager.cs
- MultiSelectRootGridEntry.cs
- StorageInfo.cs
- OutputCacheModule.cs
- CodeAttributeArgumentCollection.cs
- QueryAccessibilityHelpEvent.cs
- WebUtil.cs
- ConditionChanges.cs
- OdbcError.cs
- PopupEventArgs.cs
- DateTimeFormat.cs
- ExitEventArgs.cs
- DependencyProperty.cs
- EntityReference.cs
- InternalConfigRoot.cs
- ScopeElement.cs
- WorkerProcess.cs
- EditorZone.cs
- ReachSerializationUtils.cs
- SourceFilter.cs
- PnrpPeerResolverBindingElement.cs
- XmlTypeMapping.cs
- ListViewItemSelectionChangedEvent.cs
- UrlMapping.cs
- DocumentGridContextMenu.cs
- ImageSource.cs
- CodeExpressionCollection.cs
- EdmEntityTypeAttribute.cs
- SoapIncludeAttribute.cs
- TreeViewTemplateSelector.cs
- CursorConverter.cs
- BindingExpression.cs
- DetailsViewRow.cs
- SafeNativeMethods.cs
- ExternalException.cs
- ChildTable.cs
- TagNameToTypeMapper.cs
- XmlILModule.cs
- Operator.cs
- TraceContextEventArgs.cs
- XmlSchemaValidationException.cs
- String.cs