Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / Media / Animation / Timeline.cs / 1 / Timeline.cs
//------------------------------------------------------------------------------ // Microsoft Windows Client Platform // Copyright (c) Microsoft Corporation, 2003 // // File: Timeline.cs //----------------------------------------------------------------------------- #if DEBUG #define TRACE #endif // DEBUG using MS.Internal; using MS.Utility; using System; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Windows.Markup; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Media.Animation { ////// Describes run-time timing behavior for timed objects. /// ////// A Timeline object defines the run-time behavior of a Clock /// object. Clock objects are arranged in trees. Correspondingly, /// Timeline objects are also arranged in trees. When a tree of clocks is /// created, its structure follows that of the tree of Timeline objects. /// [RuntimeNameProperty("Name")] [Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)] // cannnot be read & localized as string public abstract partial class Timeline : Animatable { #region External interface #region Construction ////// Creates a Timeline with default properties. /// protected Timeline() { #if DEBUG lock (_debugLockObject) { _debugIdentity = ++_nextIdentity; WeakReference weakRef = new WeakReference(this); _objectTable[_debugIdentity] = weakRef; } #endif // DEBUG } ////// Creates a Timeline with the specified BeginTime. /// /// /// The scheduled BeginTime for this timeline. /// protected Timeline(NullablebeginTime) : this() { BeginTime = beginTime; } /// /// Creates a Timeline with the specified begin time and duration. /// /// /// The scheduled BeginTime for this timeline. /// /// /// The simple Duration of this timeline. /// protected Timeline(NullablebeginTime, Duration duration) : this() { BeginTime = beginTime; Duration = duration; } /// /// Creates a Timeline with the specified BeginTime, Duration and RepeatBehavior. /// /// /// The scheduled BeginTime for this Timeline. /// /// /// The simple Duration of this Timeline. /// /// /// The RepeatBehavior for this Timeline. /// protected Timeline(NullablebeginTime, Duration duration, RepeatBehavior repeatBehavior) : this() { BeginTime = beginTime; Duration = duration; RepeatBehavior = repeatBehavior; } #endregion // Construction #region Freezable /// /// Override of FreezeCore. We need to validate the timeline /// before Freezing it. /// /// protected override bool FreezeCore(bool isChecking) { ValidateTimeline(); return base.FreezeCore(isChecking); } // // Overrides for GetAsFrozenCore and GetCurrentValueAsFrozenCore // Timeline does not need to overide CloneCore and CloneCurrentValueCore // See the comment in CopyCommon // ////// Creates a frozen base value clone of another Timeline. /// /// /// The timeline to copy properties from. If this parameter is null, /// this timeline is constructed with default property values. /// ////// This method should be used by implementations of Freezable.CloneCommonCore. /// protected override void GetAsFrozenCore(Freezable sourceFreezable) { Timeline sourceTimeline = (Timeline)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(sourceTimeline); } ////// Creates a frozen current value clone of another Timeline. /// /// /// The timeline to copy properties from. If this parameter is null, /// this timeline is constructed with default property values. /// ////// This method should be used by implementations of CopyCommonCore. /// protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) { Timeline sourceTimeline = (Timeline)sourceFreezable; base.GetCurrentValueAsFrozenCore(sourceFreezable); CopyCommon(sourceTimeline); } #endregion #region Properties private static void Timeline_PropertyChangedFunction(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((Timeline)d).PropertyChanged(e.Property); } #region AccelerationRatio Property ////// AccelerationRatio Property /// public static readonly DependencyProperty AccelerationRatioProperty = DependencyProperty.Register( "AccelerationRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)0.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateAccelerationDecelerationRatio)); ////// Gets or sets a value indicating the percentage of the duration of /// an active period spent accelerating the passage of time from zero /// to its maximum rate. /// ////// The percentage of the duration of an active period spent /// accelerating the passage of time from zero to its maximum rate. /// ////// This property must be set to a value between 0 and 1, inclusive, /// or it raises an InvalidArgumentException exception. This property /// has a default value of zero. /// public double AccelerationRatio { get { return (double)GetValue(AccelerationRatioProperty); } set { SetValue(AccelerationRatioProperty, value); } } private static bool ValidateAccelerationDecelerationRatio(object value) { double newValue = (double)value; if (newValue < 0 || newValue > 1 || double.IsNaN(newValue)) { throw new ArgumentException(SR.Get(SRID.Timing_InvalidArgAccelAndDecel), "value"); } return true; } #endregion // AccelerationRatio Property #region AutoReverse Property ////// AutoReverseProperty /// public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.Register( "AutoReverse", typeof(bool), typeof(Timeline), new PropertyMetadata( false, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets a value indicating whether a normal /// forward-progressing activation period should be succeeded by a /// backward-progressing activation period. /// ////// true if a normal forward-progressing activation period should be /// succeeded by a backward-progressing activation period; otherwise, /// false. /// ////// This property has a default value of false. /// [DefaultValue(false)] public bool AutoReverse { get { return (bool)GetValue(AutoReverseProperty); } set { SetValue(AutoReverseProperty, value); } } #endregion #region BeginTime Property ////// BeginTimeProperty /// public static readonly DependencyProperty BeginTimeProperty = DependencyProperty.Register( "BeginTime", typeof(TimeSpan?), typeof(Timeline), new PropertyMetadata( (TimeSpan?)TimeSpan.Zero, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets the scheduled time at which this Timeline should /// begin, relative to its parents begin time, in local coordinates. /// ////// The scheduled time at which this Timeline should begin, relative /// to its parents begin time, in local coordinates. /// ////// This property has a default value of zero. /// public TimeSpan? BeginTime { get { return (TimeSpan?)GetValue(BeginTimeProperty); } set { SetValue(BeginTimeProperty, value); } } #endregion // BeginTime Property #region DecelerationRatio Property ////// DecelerationRatioProperty /// public static readonly DependencyProperty DecelerationRatioProperty = DependencyProperty.Register( "DecelerationRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)0.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateAccelerationDecelerationRatio)); ////// Gets or sets a value indicating the percentage of the duration /// of an active period spent decelerating the passage of time its /// maximum rate to from zero. /// ////// The percentage of the duration of an active period spent /// decelerating the passage of time its maximum rate to from zero. /// ////// This property must be set to a value between 0 and 1, inclusive, /// or it raises an InvalidArgumentException exception. This /// property has a default value of zero. /// public double DecelerationRatio { get { return (double)GetValue(DecelerationRatioProperty); } set { SetValue(DecelerationRatioProperty, value); } } #endregion // DecelerationRatio Property #region DesiredFrameRate Property ////// DesiredFrameRateProperty /// public static readonly DependencyProperty DesiredFrameRateProperty = DependencyProperty.RegisterAttached( "DesiredFrameRate", typeof(Int32?), typeof(Timeline), new PropertyMetadata( (Int32?)null, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateDesiredFrameRate)); private static bool ValidateDesiredFrameRate(object value) { Int32? desiredFrameRate = (Int32?)value; return (!desiredFrameRate.HasValue || desiredFrameRate.Value > 0); } ////// Reads the attached property DesiredFrameRate from the given Timeline. /// /// Timeline from which to read the attached property. ///The property's value. ///public static Int32? GetDesiredFrameRate(Timeline timeline) { if (timeline == null) { throw new ArgumentNullException("timeline"); } return (Int32?)timeline.GetValue(DesiredFrameRateProperty); } /// /// Writes the attached property DesiredFrameRate to the given Timeline. /// /// Timeline to which to write the attached property. /// The property value to set ///public static void SetDesiredFrameRate(Timeline timeline, Int32? desiredFrameRate) { if (timeline == null) { throw new ArgumentNullException("timeline"); } timeline.SetValue(DesiredFrameRateProperty, desiredFrameRate); } #endregion // DesiredFrameRate Property #region Duration Property /// /// DurationProperty /// public static readonly DependencyProperty DurationProperty = DependencyProperty.Register( "Duration", typeof(Duration), typeof(Timeline), new PropertyMetadata( Duration.Automatic, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets a value indicating the natural length of an /// activation period, in local coordinates. /// ////// The natural length of an activation period, in local coordinates. /// ////// This length represents a single forward or backward section of a /// single repeat iteration. This property has a default value of /// Duration.Automatic. /// public Duration Duration { get { return (Duration)GetValue(DurationProperty); } set { SetValue(DurationProperty, value); } } #endregion // Duration Property #region FillBehavior Property ////// FillBehavior Property /// public static readonly DependencyProperty FillBehaviorProperty = DependencyProperty.Register( "FillBehavior", typeof(FillBehavior), typeof(Timeline), new PropertyMetadata( FillBehavior.HoldEnd, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateFillBehavior)); private static bool ValidateFillBehavior(object value) { return TimeEnumHelper.IsValidFillBehavior((FillBehavior)value); } ////// This property indicates how a Timeline will behave when it is outside /// of its active period but its parent is in its active or hold period. /// ///public FillBehavior FillBehavior { get { return (FillBehavior)GetValue(FillBehaviorProperty); } set { SetValue(FillBehaviorProperty, value); } } #endregion // FillBehavior Property #region Name Property /// /// Name Property /// public static readonly DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof(string), typeof(Timeline), new PropertyMetadata( (string)null, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(System.Windows.Markup.NameValidationHelper.NameValidationCallback)); ////// Gets or sets the Name of this Timeline. /// ////// The Name of this Timeline. /// ////// This property can be used to set up [....]-arcs between sibling /// Timeline objects. A [....]-arc is established when the /// [DefaultValue((string)null)] [MergableProperty(false)] public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } } #endregion // Name Property #region RepeatBehavior Property ///property of one Timeline /// corresponds to the Name of another Timeline. /// /// RepeatBehaviorProperty /// public static readonly DependencyProperty RepeatBehaviorProperty = DependencyProperty.Register( "RepeatBehavior", typeof(RepeatBehavior), typeof(Timeline), new PropertyMetadata( new RepeatBehavior(1.0), new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets the a RepeatBehavior structure which specifies the way this Timeline will /// repeat its simple duration. /// ///A RepeatBehavior structure which specifies the way this Timeline will repeat its /// simple duration. public RepeatBehavior RepeatBehavior { get { return (RepeatBehavior)GetValue(RepeatBehaviorProperty); } set { SetValue(RepeatBehaviorProperty, value); } } #endregion // RepeatBehavior Property #region SpeedRatio Property ////// SpeedRatioProperty /// public static readonly DependencyProperty SpeedRatioProperty = DependencyProperty.Register( "SpeedRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)1.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateSpeedRatio)); ////// Gets or sets the ratio at which time progresses on this Timeline, /// relative to its parent. /// ////// The ratio at which time progresses on this Timeline, relative to /// its parent. /// ////// If Acceleration or Deceleration are specified, this ratio is the /// average ratio over the natural length of the Timeline. This /// property has a default value of 1.0. /// [DefaultValue((double)1.0)] public double SpeedRatio { get { return (double)GetValue(SpeedRatioProperty); } set { SetValue(SpeedRatioProperty, value); } } private static bool ValidateSpeedRatio(object value) { double newValue = (double)value; if (newValue <= 0 || newValue > double.MaxValue || double.IsNaN(newValue)) { throw new ArgumentException(SR.Get(SRID.Timing_InvalidArgFinitePositive), "value"); } return true; } #endregion // SpeedRatio Property #endregion // Properties #region Methods ////// Called by the ///method to /// create a type-specific clock for this Timeline. /// /// A clock for this Timeline. /// ////// If a derived class overrides this method, it should only create /// and return an object of a class inheriting from Clock. /// protected internal virtual Clock AllocateClock() { return new Clock(this); } ////// Creates a new Clock using this Timeline as the root. If this /// Timeline has children, a tree of clocks will be created. /// ////// Although this Timeline may be included as a child of one or more /// TimelineGroups, this information will be ignored. For the purposes /// of this method this Timeline will be treated as a root Timeline. /// ////// A new Clock or tree of Clocks depending on whether /// or not this Timeline is a TimelineGroup that contains children. /// public Clock CreateClock() { return CreateClock(true); } ////// Creates a new Clock using this Timeline as the root. If this /// Timeline has children, a tree of clocks will be created. /// /// True if the root Clock returned should /// return a ClockController from its Controller property so that /// the Clock tree can be interactively controlled. ////// Although this Timeline may be included as a child of one or more /// TimelineGroups, this information will be ignored. For the purposes /// of this method this Timeline will be treated as a root Timeline. /// ////// A new Clock or tree of Clocks depending on whether /// or not this Timeline is a TimelineGroup that contains children. /// public Clock CreateClock(bool hasControllableRoot) { // Create the tree of clocks from this timeline return Clock.BuildClockTreeFromTimeline(this, hasControllableRoot); } ////// Returns the period of a single iteration. This will only be called when /// the Duration property is set to Automatic. If Duration is Automatic, /// the natural duration is determined by the nature of the specific timeline class, /// as determined by its author. If GetNaturalDuration returns Automatic, it means /// that the natural duration is unknown, which temporarily implies Forever. /// Streaming media would fit this case. /// /// /// The Clock whose natural duration is desired. /// ////// A Duration quantity representing the natural duration. /// internal protected Duration GetNaturalDuration(Clock clock) { return GetNaturalDurationCore(clock); } ////// Implemented by the class author to provide a custom natural Duration /// in the case that the Duration property is set to Automatic. If the author /// cannot determine the Duration, this method should return Automatic. /// /// /// The Clock whose natural duration is desired. /// ////// A Duration quantity representing the natural duration. /// protected virtual Duration GetNaturalDurationCore(Clock clock) { return Duration.Automatic; } ////// This method will throw an exception if a timeline has been incorrectly /// constructed. Currently we validate all possible values when they are /// set, but it is not possible to do this for Acceleration/DecelerationRatio. /// /// The reason is when a timeline is instantiated in xaml the properties are /// set with direct calls to DependencyObject.SetValue. This means our only /// chance to validate the value is in the ValidateValue callback, which does /// not allow querying of other DPs. Acceleration/DecelerationRatio are invalid /// if their sum is > 1. This can't be verified in the ValidateValue callback, /// so is done here. /// private void ValidateTimeline() { if (AccelerationRatio + DecelerationRatio > 1) { throw new InvalidOperationException(SR.Get(SRID.Timing_AccelAndDecelGreaterThanOne)); } } #endregion // Methods #region Events ////// Raised whenever the value of the CurrentStateInvalidated property changes. /// public event EventHandler CurrentStateInvalidated { add { AddEventHandler(CurrentStateInvalidatedKey, value); } remove { RemoveEventHandler(CurrentStateInvalidatedKey, value); } } ////// Raised whenever the value of the CurrentTimeInvalidated property changes. /// public event EventHandler CurrentTimeInvalidated { add { AddEventHandler(CurrentTimeInvalidatedKey, value); } remove { RemoveEventHandler(CurrentTimeInvalidatedKey, value); } } ////// Raised whenever the value of the CurrentGlobalSpeed property changes. /// public event EventHandler CurrentGlobalSpeedInvalidated { add { AddEventHandler(CurrentGlobalSpeedInvalidatedKey, value); } remove { RemoveEventHandler(CurrentGlobalSpeedInvalidatedKey, value); } } ////// Raised whenever the value of the Completed property changes. /// public event EventHandler Completed { add { AddEventHandler(CompletedKey, value); } remove { RemoveEventHandler(CompletedKey, value); } } ////// Raised whenever the value of the RemoveRequested property changes. /// public event EventHandler RemoveRequested { add { AddEventHandler(RemoveRequestedKey, value); } remove { RemoveEventHandler(RemoveRequestedKey, value); } } #endregion // Events #endregion // External interface #region Internal implementation #region Properties ////// Read-only access to the EventHandlerStore. Used by /// Clock to copy the Timeline's events /// internal EventHandlersStore InternalEventHandlersStore { get { return EventHandlersStoreField.GetValue(this); } } #endregion // Properties #region Methods ////// Exposes the OnFreezablePropertyChanged protected method for use /// by the TimelineCollection class. /// /// /// The previous value of the timeline. /// /// /// The new value of the timeline. /// internal void InternalOnFreezablePropertyChanged(Timeline originalTimeline, Timeline newTimeline) { OnFreezablePropertyChanged(originalTimeline, newTimeline); } ////// Called by the TimelineCollection class to propagate the /// Freezable.FreezeCore call to this object. /// internal bool InternalFreeze(bool isChecking) { return Freeze(this, isChecking); } ////// Asks this timeline to perform read verification. /// internal void InternalReadPreamble() { ReadPreamble(); } ////// Notifies this timeline that a change has been made. /// internal void InternalWritePostscript() { WritePostscript(); } ////// Adds a delegate to the list of event handlers on this object. /// /// /// A unique identifier for the event handler. /// /// The delegate to add. private void AddEventHandler(EventPrivateKey key, Delegate handler) { WritePreamble(); EventHandlersStore store = EventHandlersStoreField.GetValue(this); if (store == null) { store = new EventHandlersStore(); EventHandlersStoreField.SetValue(this, store); } store.Add(key, handler); WritePostscript(); } ////// Implements copy functionalty for GetAsFrozenCore and GetCurrentValueAsFrozenCore /// Timeline does not need to override CloneCore and CloneCurrentValueCore. /// /// private void CopyCommon(Timeline sourceTimeline) { // When creating a frozen copy of a Timeline we want to copy the // event handlers. This is for two reasons // // 1.) Internally when creating a clock tree we use // a frozen copy of the timing tree. If that frozen // copy does not preserve the event handlers then // any callbacks registered on the Timelines will be lost. // // 2.) GetAsFrozen and GetCurrentValueAsFrozen don't always clone. // If any object in the tree is frozen it'll simply return it. // If we did not copy the event handlers GetAsFrozen // would return different results depending on whether a // Timeline was frozen before the call. // // // The other two clone methods make unfrozen clones, so it's consisent // to not copy the event handlers for those methods. Cloning an object // is basically the only way to get a 'fresh' copy without event handlers // attached. If someone wants a frozen clone they probably want an exact // copy of the original. EventHandlersStore sourceStore = EventHandlersStoreField.GetValue(sourceTimeline); if (sourceStore != null) { Debug.Assert(sourceStore.Count > 0); EventHandlersStoreField.SetValue(this, new EventHandlersStore(sourceStore)); } } ////// Removes a delegate from the list of event handlers on this object. /// /// /// A unique identifier for the event handler. /// /// The delegate to remove. private void RemoveEventHandler(EventPrivateKey key, Delegate handler) { WritePreamble(); EventHandlersStore store = EventHandlersStoreField.GetValue(this); if (store != null) { store.Remove(key, handler); if (store.Count == 0) { // last event handler was removed -- throw away underlying EventHandlersStore EventHandlersStoreField.ClearValue(this); } WritePostscript(); } } #endregion // Methods #region Debugging instrumentation #if DEBUG ////// Dumps the description of the subtree rooted at this timeline. /// internal void Dump() { System.Text.StringBuilder builder = new System.Text.StringBuilder(); builder.Capacity = 1024; builder.Append("========================================\n"); builder.Append("Timelines rooted at Timeline "); builder.Append(_debugIdentity); builder.Append('\n'); builder.Append("----------------------------------------\n"); BuildInfoRecursive(builder, 0); builder.Append("----------------------------------------\n"); Trace.Write(builder.ToString()); } ////// Dumps the description of all timelines in the known timeline table. /// internal static void DumpAll() { System.Text.StringBuilder builder = new System.Text.StringBuilder(); int timelineCount = 0; builder.Capacity = 1024; builder.Append("========================================\n"); builder.Append("Timelines in the GC heap\n"); builder.Append("----------------------------------------\n"); lock (_debugLockObject) { if (_objectTable.Count > 0) { // Output the timelines sorted by Name int[] idTable = new int[_objectTable.Count]; _objectTable.Keys.CopyTo(idTable, 0); Array.Sort(idTable); for (int index = 0; index < idTable.Length; index++) { WeakReference weakRef = (WeakReference)_objectTable[idTable[index]]; Timeline timeline = (Timeline)weakRef.Target; if (timeline != null) { timeline.BuildInfo(builder, 0, true); timelineCount++; } } } } if (timelineCount == 0) { builder.Append("There are no Timelines in the GC heap.\n"); } builder.Append("----------------------------------------\n"); Trace.Write(builder.ToString()); } ////// Dumps the description of the subtree rooted at this timeline. /// /// /// A StringBuilder that accumulates the description text. /// /// /// The depth of recursion for this timeline. /// internal void BuildInfoRecursive(System.Text.StringBuilder builder, int depth) { // Add the info for this timeline BuildInfo(builder, depth, true); // Recurse into the children depth++; TimelineGroup timelineGroup = this as TimelineGroup; if (timelineGroup != null) { TimelineCollection children = timelineGroup.Children; if (children != null) { for (int childIndex = 0; childIndex < children.Count; childIndex++) { children.Internal_GetItem(childIndex).BuildInfoRecursive(builder, depth); } } } } ////// Dumps the description of this timeline. /// /// /// A StringBuilder that accumulates the description text. /// /// /// The depth of recursion for this timeline. /// /// /// Whether or not to include the debug ID in the description. /// internal void BuildInfo(System.Text.StringBuilder builder, int depth, bool includeDebugID) { // Start with the name of the timeline if (includeDebugID) { builder.Append(' ', depth); builder.Append("Timeline "); builder.Append(_debugIdentity); } builder.Append(" ("); builder.Append(GetType().Name); // Build attributes if (Name != null) { builder.Append(", Name=\""); builder.Append(Name); builder.Append("\""); } if (AccelerationRatio != 0.0f) { builder.Append(", AccelerationRatio = "); builder.Append(AccelerationRatio.ToString()); } if (AutoReverse != false) { builder.Append(", AutoReverse = "); builder.Append(AutoReverse.ToString()); } if (DecelerationRatio != 0.0f) { builder.Append(", DecelerationRatio = "); builder.Append(DecelerationRatio.ToString()); } if (Duration != Duration.Automatic) { builder.Append(", Duration = "); builder.Append(Duration.ToString()); } if (FillBehavior != FillBehavior.HoldEnd) { builder.Append(", FillBehavior = "); builder.Append(FillBehavior.ToString()); } if (SpeedRatio != 1.0f) { builder.Append(", Speed = "); builder.Append(SpeedRatio); } builder.Append(")\n"); } ////// Finds a previously registered object. /// /// /// The Name of the object to look for /// ////// The object if found, null otherwise. /// internal static Timeline Find(int id) { Timeline timeline = null; lock (_debugLockObject) { object handleReference = _objectTable[id]; if (handleReference != null) { WeakReference weakRef = (WeakReference)handleReference; timeline = (Timeline)weakRef.Target; if (timeline == null) { // Object has been destroyed, so remove the weakRef. _objectTable.Remove(id); } } } return timeline; } ////// Cleans up the known timelines table by removing dead weak /// references. /// internal static void CleanKnownTimelinesTable() { lock (_debugLockObject) { Hashtable removeTable = new Hashtable(); // Identify dead references foreach (DictionaryEntry e in _objectTable) { WeakReference weakRef = (WeakReference) e.Value; if (weakRef.Target == null) { removeTable[e.Key] = weakRef; } } // Remove dead references foreach (DictionaryEntry e in removeTable) { _objectTable.Remove(e.Key); } } } #endif // DEBUG #endregion // Debugging instrumentation #region Data #region Event Handler Storage internal static readonly UncommonFieldEventHandlersStoreField = new UncommonField (); // Unique identifiers for each of the events defined on Timeline. // This is used as a key in the EventHandlerStore internal static readonly EventPrivateKey CurrentGlobalSpeedInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CurrentStateInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CurrentTimeInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CompletedKey = new EventPrivateKey(); internal static readonly EventPrivateKey RemoveRequestedKey = new EventPrivateKey(); #endregion // Event Handler Storage #region Debug data #if DEBUG internal int _debugIdentity; internal static int _nextIdentity; internal static Hashtable _objectTable = new Hashtable(); internal static object _debugLockObject = new object(); #endif // DEBUG #endregion // Debug data #endregion // Data #endregion // Internal implementation } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Microsoft Windows Client Platform // Copyright (c) Microsoft Corporation, 2003 // // File: Timeline.cs //----------------------------------------------------------------------------- #if DEBUG #define TRACE #endif // DEBUG using MS.Internal; using MS.Utility; using System; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Windows.Markup; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Media.Animation { /// /// Describes run-time timing behavior for timed objects. /// ////// A Timeline object defines the run-time behavior of a Clock /// object. Clock objects are arranged in trees. Correspondingly, /// Timeline objects are also arranged in trees. When a tree of clocks is /// created, its structure follows that of the tree of Timeline objects. /// [RuntimeNameProperty("Name")] [Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)] // cannnot be read & localized as string public abstract partial class Timeline : Animatable { #region External interface #region Construction ////// Creates a Timeline with default properties. /// protected Timeline() { #if DEBUG lock (_debugLockObject) { _debugIdentity = ++_nextIdentity; WeakReference weakRef = new WeakReference(this); _objectTable[_debugIdentity] = weakRef; } #endif // DEBUG } ////// Creates a Timeline with the specified BeginTime. /// /// /// The scheduled BeginTime for this timeline. /// protected Timeline(NullablebeginTime) : this() { BeginTime = beginTime; } /// /// Creates a Timeline with the specified begin time and duration. /// /// /// The scheduled BeginTime for this timeline. /// /// /// The simple Duration of this timeline. /// protected Timeline(NullablebeginTime, Duration duration) : this() { BeginTime = beginTime; Duration = duration; } /// /// Creates a Timeline with the specified BeginTime, Duration and RepeatBehavior. /// /// /// The scheduled BeginTime for this Timeline. /// /// /// The simple Duration of this Timeline. /// /// /// The RepeatBehavior for this Timeline. /// protected Timeline(NullablebeginTime, Duration duration, RepeatBehavior repeatBehavior) : this() { BeginTime = beginTime; Duration = duration; RepeatBehavior = repeatBehavior; } #endregion // Construction #region Freezable /// /// Override of FreezeCore. We need to validate the timeline /// before Freezing it. /// /// protected override bool FreezeCore(bool isChecking) { ValidateTimeline(); return base.FreezeCore(isChecking); } // // Overrides for GetAsFrozenCore and GetCurrentValueAsFrozenCore // Timeline does not need to overide CloneCore and CloneCurrentValueCore // See the comment in CopyCommon // ////// Creates a frozen base value clone of another Timeline. /// /// /// The timeline to copy properties from. If this parameter is null, /// this timeline is constructed with default property values. /// ////// This method should be used by implementations of Freezable.CloneCommonCore. /// protected override void GetAsFrozenCore(Freezable sourceFreezable) { Timeline sourceTimeline = (Timeline)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(sourceTimeline); } ////// Creates a frozen current value clone of another Timeline. /// /// /// The timeline to copy properties from. If this parameter is null, /// this timeline is constructed with default property values. /// ////// This method should be used by implementations of CopyCommonCore. /// protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) { Timeline sourceTimeline = (Timeline)sourceFreezable; base.GetCurrentValueAsFrozenCore(sourceFreezable); CopyCommon(sourceTimeline); } #endregion #region Properties private static void Timeline_PropertyChangedFunction(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((Timeline)d).PropertyChanged(e.Property); } #region AccelerationRatio Property ////// AccelerationRatio Property /// public static readonly DependencyProperty AccelerationRatioProperty = DependencyProperty.Register( "AccelerationRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)0.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateAccelerationDecelerationRatio)); ////// Gets or sets a value indicating the percentage of the duration of /// an active period spent accelerating the passage of time from zero /// to its maximum rate. /// ////// The percentage of the duration of an active period spent /// accelerating the passage of time from zero to its maximum rate. /// ////// This property must be set to a value between 0 and 1, inclusive, /// or it raises an InvalidArgumentException exception. This property /// has a default value of zero. /// public double AccelerationRatio { get { return (double)GetValue(AccelerationRatioProperty); } set { SetValue(AccelerationRatioProperty, value); } } private static bool ValidateAccelerationDecelerationRatio(object value) { double newValue = (double)value; if (newValue < 0 || newValue > 1 || double.IsNaN(newValue)) { throw new ArgumentException(SR.Get(SRID.Timing_InvalidArgAccelAndDecel), "value"); } return true; } #endregion // AccelerationRatio Property #region AutoReverse Property ////// AutoReverseProperty /// public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.Register( "AutoReverse", typeof(bool), typeof(Timeline), new PropertyMetadata( false, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets a value indicating whether a normal /// forward-progressing activation period should be succeeded by a /// backward-progressing activation period. /// ////// true if a normal forward-progressing activation period should be /// succeeded by a backward-progressing activation period; otherwise, /// false. /// ////// This property has a default value of false. /// [DefaultValue(false)] public bool AutoReverse { get { return (bool)GetValue(AutoReverseProperty); } set { SetValue(AutoReverseProperty, value); } } #endregion #region BeginTime Property ////// BeginTimeProperty /// public static readonly DependencyProperty BeginTimeProperty = DependencyProperty.Register( "BeginTime", typeof(TimeSpan?), typeof(Timeline), new PropertyMetadata( (TimeSpan?)TimeSpan.Zero, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets the scheduled time at which this Timeline should /// begin, relative to its parents begin time, in local coordinates. /// ////// The scheduled time at which this Timeline should begin, relative /// to its parents begin time, in local coordinates. /// ////// This property has a default value of zero. /// public TimeSpan? BeginTime { get { return (TimeSpan?)GetValue(BeginTimeProperty); } set { SetValue(BeginTimeProperty, value); } } #endregion // BeginTime Property #region DecelerationRatio Property ////// DecelerationRatioProperty /// public static readonly DependencyProperty DecelerationRatioProperty = DependencyProperty.Register( "DecelerationRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)0.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateAccelerationDecelerationRatio)); ////// Gets or sets a value indicating the percentage of the duration /// of an active period spent decelerating the passage of time its /// maximum rate to from zero. /// ////// The percentage of the duration of an active period spent /// decelerating the passage of time its maximum rate to from zero. /// ////// This property must be set to a value between 0 and 1, inclusive, /// or it raises an InvalidArgumentException exception. This /// property has a default value of zero. /// public double DecelerationRatio { get { return (double)GetValue(DecelerationRatioProperty); } set { SetValue(DecelerationRatioProperty, value); } } #endregion // DecelerationRatio Property #region DesiredFrameRate Property ////// DesiredFrameRateProperty /// public static readonly DependencyProperty DesiredFrameRateProperty = DependencyProperty.RegisterAttached( "DesiredFrameRate", typeof(Int32?), typeof(Timeline), new PropertyMetadata( (Int32?)null, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateDesiredFrameRate)); private static bool ValidateDesiredFrameRate(object value) { Int32? desiredFrameRate = (Int32?)value; return (!desiredFrameRate.HasValue || desiredFrameRate.Value > 0); } ////// Reads the attached property DesiredFrameRate from the given Timeline. /// /// Timeline from which to read the attached property. ///The property's value. ///public static Int32? GetDesiredFrameRate(Timeline timeline) { if (timeline == null) { throw new ArgumentNullException("timeline"); } return (Int32?)timeline.GetValue(DesiredFrameRateProperty); } /// /// Writes the attached property DesiredFrameRate to the given Timeline. /// /// Timeline to which to write the attached property. /// The property value to set ///public static void SetDesiredFrameRate(Timeline timeline, Int32? desiredFrameRate) { if (timeline == null) { throw new ArgumentNullException("timeline"); } timeline.SetValue(DesiredFrameRateProperty, desiredFrameRate); } #endregion // DesiredFrameRate Property #region Duration Property /// /// DurationProperty /// public static readonly DependencyProperty DurationProperty = DependencyProperty.Register( "Duration", typeof(Duration), typeof(Timeline), new PropertyMetadata( Duration.Automatic, new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets a value indicating the natural length of an /// activation period, in local coordinates. /// ////// The natural length of an activation period, in local coordinates. /// ////// This length represents a single forward or backward section of a /// single repeat iteration. This property has a default value of /// Duration.Automatic. /// public Duration Duration { get { return (Duration)GetValue(DurationProperty); } set { SetValue(DurationProperty, value); } } #endregion // Duration Property #region FillBehavior Property ////// FillBehavior Property /// public static readonly DependencyProperty FillBehaviorProperty = DependencyProperty.Register( "FillBehavior", typeof(FillBehavior), typeof(Timeline), new PropertyMetadata( FillBehavior.HoldEnd, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateFillBehavior)); private static bool ValidateFillBehavior(object value) { return TimeEnumHelper.IsValidFillBehavior((FillBehavior)value); } ////// This property indicates how a Timeline will behave when it is outside /// of its active period but its parent is in its active or hold period. /// ///public FillBehavior FillBehavior { get { return (FillBehavior)GetValue(FillBehaviorProperty); } set { SetValue(FillBehaviorProperty, value); } } #endregion // FillBehavior Property #region Name Property /// /// Name Property /// public static readonly DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof(string), typeof(Timeline), new PropertyMetadata( (string)null, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(System.Windows.Markup.NameValidationHelper.NameValidationCallback)); ////// Gets or sets the Name of this Timeline. /// ////// The Name of this Timeline. /// ////// This property can be used to set up [....]-arcs between sibling /// Timeline objects. A [....]-arc is established when the /// [DefaultValue((string)null)] [MergableProperty(false)] public string Name { get { return (string)GetValue(NameProperty); } set { SetValue(NameProperty, value); } } #endregion // Name Property #region RepeatBehavior Property ///property of one Timeline /// corresponds to the Name of another Timeline. /// /// RepeatBehaviorProperty /// public static readonly DependencyProperty RepeatBehaviorProperty = DependencyProperty.Register( "RepeatBehavior", typeof(RepeatBehavior), typeof(Timeline), new PropertyMetadata( new RepeatBehavior(1.0), new PropertyChangedCallback(Timeline_PropertyChangedFunction))); ////// Gets or sets the a RepeatBehavior structure which specifies the way this Timeline will /// repeat its simple duration. /// ///A RepeatBehavior structure which specifies the way this Timeline will repeat its /// simple duration. public RepeatBehavior RepeatBehavior { get { return (RepeatBehavior)GetValue(RepeatBehaviorProperty); } set { SetValue(RepeatBehaviorProperty, value); } } #endregion // RepeatBehavior Property #region SpeedRatio Property ////// SpeedRatioProperty /// public static readonly DependencyProperty SpeedRatioProperty = DependencyProperty.Register( "SpeedRatio", typeof(double), typeof(Timeline), new PropertyMetadata( (double)1.0, new PropertyChangedCallback(Timeline_PropertyChangedFunction)), new ValidateValueCallback(ValidateSpeedRatio)); ////// Gets or sets the ratio at which time progresses on this Timeline, /// relative to its parent. /// ////// The ratio at which time progresses on this Timeline, relative to /// its parent. /// ////// If Acceleration or Deceleration are specified, this ratio is the /// average ratio over the natural length of the Timeline. This /// property has a default value of 1.0. /// [DefaultValue((double)1.0)] public double SpeedRatio { get { return (double)GetValue(SpeedRatioProperty); } set { SetValue(SpeedRatioProperty, value); } } private static bool ValidateSpeedRatio(object value) { double newValue = (double)value; if (newValue <= 0 || newValue > double.MaxValue || double.IsNaN(newValue)) { throw new ArgumentException(SR.Get(SRID.Timing_InvalidArgFinitePositive), "value"); } return true; } #endregion // SpeedRatio Property #endregion // Properties #region Methods ////// Called by the ///method to /// create a type-specific clock for this Timeline. /// /// A clock for this Timeline. /// ////// If a derived class overrides this method, it should only create /// and return an object of a class inheriting from Clock. /// protected internal virtual Clock AllocateClock() { return new Clock(this); } ////// Creates a new Clock using this Timeline as the root. If this /// Timeline has children, a tree of clocks will be created. /// ////// Although this Timeline may be included as a child of one or more /// TimelineGroups, this information will be ignored. For the purposes /// of this method this Timeline will be treated as a root Timeline. /// ////// A new Clock or tree of Clocks depending on whether /// or not this Timeline is a TimelineGroup that contains children. /// public Clock CreateClock() { return CreateClock(true); } ////// Creates a new Clock using this Timeline as the root. If this /// Timeline has children, a tree of clocks will be created. /// /// True if the root Clock returned should /// return a ClockController from its Controller property so that /// the Clock tree can be interactively controlled. ////// Although this Timeline may be included as a child of one or more /// TimelineGroups, this information will be ignored. For the purposes /// of this method this Timeline will be treated as a root Timeline. /// ////// A new Clock or tree of Clocks depending on whether /// or not this Timeline is a TimelineGroup that contains children. /// public Clock CreateClock(bool hasControllableRoot) { // Create the tree of clocks from this timeline return Clock.BuildClockTreeFromTimeline(this, hasControllableRoot); } ////// Returns the period of a single iteration. This will only be called when /// the Duration property is set to Automatic. If Duration is Automatic, /// the natural duration is determined by the nature of the specific timeline class, /// as determined by its author. If GetNaturalDuration returns Automatic, it means /// that the natural duration is unknown, which temporarily implies Forever. /// Streaming media would fit this case. /// /// /// The Clock whose natural duration is desired. /// ////// A Duration quantity representing the natural duration. /// internal protected Duration GetNaturalDuration(Clock clock) { return GetNaturalDurationCore(clock); } ////// Implemented by the class author to provide a custom natural Duration /// in the case that the Duration property is set to Automatic. If the author /// cannot determine the Duration, this method should return Automatic. /// /// /// The Clock whose natural duration is desired. /// ////// A Duration quantity representing the natural duration. /// protected virtual Duration GetNaturalDurationCore(Clock clock) { return Duration.Automatic; } ////// This method will throw an exception if a timeline has been incorrectly /// constructed. Currently we validate all possible values when they are /// set, but it is not possible to do this for Acceleration/DecelerationRatio. /// /// The reason is when a timeline is instantiated in xaml the properties are /// set with direct calls to DependencyObject.SetValue. This means our only /// chance to validate the value is in the ValidateValue callback, which does /// not allow querying of other DPs. Acceleration/DecelerationRatio are invalid /// if their sum is > 1. This can't be verified in the ValidateValue callback, /// so is done here. /// private void ValidateTimeline() { if (AccelerationRatio + DecelerationRatio > 1) { throw new InvalidOperationException(SR.Get(SRID.Timing_AccelAndDecelGreaterThanOne)); } } #endregion // Methods #region Events ////// Raised whenever the value of the CurrentStateInvalidated property changes. /// public event EventHandler CurrentStateInvalidated { add { AddEventHandler(CurrentStateInvalidatedKey, value); } remove { RemoveEventHandler(CurrentStateInvalidatedKey, value); } } ////// Raised whenever the value of the CurrentTimeInvalidated property changes. /// public event EventHandler CurrentTimeInvalidated { add { AddEventHandler(CurrentTimeInvalidatedKey, value); } remove { RemoveEventHandler(CurrentTimeInvalidatedKey, value); } } ////// Raised whenever the value of the CurrentGlobalSpeed property changes. /// public event EventHandler CurrentGlobalSpeedInvalidated { add { AddEventHandler(CurrentGlobalSpeedInvalidatedKey, value); } remove { RemoveEventHandler(CurrentGlobalSpeedInvalidatedKey, value); } } ////// Raised whenever the value of the Completed property changes. /// public event EventHandler Completed { add { AddEventHandler(CompletedKey, value); } remove { RemoveEventHandler(CompletedKey, value); } } ////// Raised whenever the value of the RemoveRequested property changes. /// public event EventHandler RemoveRequested { add { AddEventHandler(RemoveRequestedKey, value); } remove { RemoveEventHandler(RemoveRequestedKey, value); } } #endregion // Events #endregion // External interface #region Internal implementation #region Properties ////// Read-only access to the EventHandlerStore. Used by /// Clock to copy the Timeline's events /// internal EventHandlersStore InternalEventHandlersStore { get { return EventHandlersStoreField.GetValue(this); } } #endregion // Properties #region Methods ////// Exposes the OnFreezablePropertyChanged protected method for use /// by the TimelineCollection class. /// /// /// The previous value of the timeline. /// /// /// The new value of the timeline. /// internal void InternalOnFreezablePropertyChanged(Timeline originalTimeline, Timeline newTimeline) { OnFreezablePropertyChanged(originalTimeline, newTimeline); } ////// Called by the TimelineCollection class to propagate the /// Freezable.FreezeCore call to this object. /// internal bool InternalFreeze(bool isChecking) { return Freeze(this, isChecking); } ////// Asks this timeline to perform read verification. /// internal void InternalReadPreamble() { ReadPreamble(); } ////// Notifies this timeline that a change has been made. /// internal void InternalWritePostscript() { WritePostscript(); } ////// Adds a delegate to the list of event handlers on this object. /// /// /// A unique identifier for the event handler. /// /// The delegate to add. private void AddEventHandler(EventPrivateKey key, Delegate handler) { WritePreamble(); EventHandlersStore store = EventHandlersStoreField.GetValue(this); if (store == null) { store = new EventHandlersStore(); EventHandlersStoreField.SetValue(this, store); } store.Add(key, handler); WritePostscript(); } ////// Implements copy functionalty for GetAsFrozenCore and GetCurrentValueAsFrozenCore /// Timeline does not need to override CloneCore and CloneCurrentValueCore. /// /// private void CopyCommon(Timeline sourceTimeline) { // When creating a frozen copy of a Timeline we want to copy the // event handlers. This is for two reasons // // 1.) Internally when creating a clock tree we use // a frozen copy of the timing tree. If that frozen // copy does not preserve the event handlers then // any callbacks registered on the Timelines will be lost. // // 2.) GetAsFrozen and GetCurrentValueAsFrozen don't always clone. // If any object in the tree is frozen it'll simply return it. // If we did not copy the event handlers GetAsFrozen // would return different results depending on whether a // Timeline was frozen before the call. // // // The other two clone methods make unfrozen clones, so it's consisent // to not copy the event handlers for those methods. Cloning an object // is basically the only way to get a 'fresh' copy without event handlers // attached. If someone wants a frozen clone they probably want an exact // copy of the original. EventHandlersStore sourceStore = EventHandlersStoreField.GetValue(sourceTimeline); if (sourceStore != null) { Debug.Assert(sourceStore.Count > 0); EventHandlersStoreField.SetValue(this, new EventHandlersStore(sourceStore)); } } ////// Removes a delegate from the list of event handlers on this object. /// /// /// A unique identifier for the event handler. /// /// The delegate to remove. private void RemoveEventHandler(EventPrivateKey key, Delegate handler) { WritePreamble(); EventHandlersStore store = EventHandlersStoreField.GetValue(this); if (store != null) { store.Remove(key, handler); if (store.Count == 0) { // last event handler was removed -- throw away underlying EventHandlersStore EventHandlersStoreField.ClearValue(this); } WritePostscript(); } } #endregion // Methods #region Debugging instrumentation #if DEBUG ////// Dumps the description of the subtree rooted at this timeline. /// internal void Dump() { System.Text.StringBuilder builder = new System.Text.StringBuilder(); builder.Capacity = 1024; builder.Append("========================================\n"); builder.Append("Timelines rooted at Timeline "); builder.Append(_debugIdentity); builder.Append('\n'); builder.Append("----------------------------------------\n"); BuildInfoRecursive(builder, 0); builder.Append("----------------------------------------\n"); Trace.Write(builder.ToString()); } ////// Dumps the description of all timelines in the known timeline table. /// internal static void DumpAll() { System.Text.StringBuilder builder = new System.Text.StringBuilder(); int timelineCount = 0; builder.Capacity = 1024; builder.Append("========================================\n"); builder.Append("Timelines in the GC heap\n"); builder.Append("----------------------------------------\n"); lock (_debugLockObject) { if (_objectTable.Count > 0) { // Output the timelines sorted by Name int[] idTable = new int[_objectTable.Count]; _objectTable.Keys.CopyTo(idTable, 0); Array.Sort(idTable); for (int index = 0; index < idTable.Length; index++) { WeakReference weakRef = (WeakReference)_objectTable[idTable[index]]; Timeline timeline = (Timeline)weakRef.Target; if (timeline != null) { timeline.BuildInfo(builder, 0, true); timelineCount++; } } } } if (timelineCount == 0) { builder.Append("There are no Timelines in the GC heap.\n"); } builder.Append("----------------------------------------\n"); Trace.Write(builder.ToString()); } ////// Dumps the description of the subtree rooted at this timeline. /// /// /// A StringBuilder that accumulates the description text. /// /// /// The depth of recursion for this timeline. /// internal void BuildInfoRecursive(System.Text.StringBuilder builder, int depth) { // Add the info for this timeline BuildInfo(builder, depth, true); // Recurse into the children depth++; TimelineGroup timelineGroup = this as TimelineGroup; if (timelineGroup != null) { TimelineCollection children = timelineGroup.Children; if (children != null) { for (int childIndex = 0; childIndex < children.Count; childIndex++) { children.Internal_GetItem(childIndex).BuildInfoRecursive(builder, depth); } } } } ////// Dumps the description of this timeline. /// /// /// A StringBuilder that accumulates the description text. /// /// /// The depth of recursion for this timeline. /// /// /// Whether or not to include the debug ID in the description. /// internal void BuildInfo(System.Text.StringBuilder builder, int depth, bool includeDebugID) { // Start with the name of the timeline if (includeDebugID) { builder.Append(' ', depth); builder.Append("Timeline "); builder.Append(_debugIdentity); } builder.Append(" ("); builder.Append(GetType().Name); // Build attributes if (Name != null) { builder.Append(", Name=\""); builder.Append(Name); builder.Append("\""); } if (AccelerationRatio != 0.0f) { builder.Append(", AccelerationRatio = "); builder.Append(AccelerationRatio.ToString()); } if (AutoReverse != false) { builder.Append(", AutoReverse = "); builder.Append(AutoReverse.ToString()); } if (DecelerationRatio != 0.0f) { builder.Append(", DecelerationRatio = "); builder.Append(DecelerationRatio.ToString()); } if (Duration != Duration.Automatic) { builder.Append(", Duration = "); builder.Append(Duration.ToString()); } if (FillBehavior != FillBehavior.HoldEnd) { builder.Append(", FillBehavior = "); builder.Append(FillBehavior.ToString()); } if (SpeedRatio != 1.0f) { builder.Append(", Speed = "); builder.Append(SpeedRatio); } builder.Append(")\n"); } ////// Finds a previously registered object. /// /// /// The Name of the object to look for /// ////// The object if found, null otherwise. /// internal static Timeline Find(int id) { Timeline timeline = null; lock (_debugLockObject) { object handleReference = _objectTable[id]; if (handleReference != null) { WeakReference weakRef = (WeakReference)handleReference; timeline = (Timeline)weakRef.Target; if (timeline == null) { // Object has been destroyed, so remove the weakRef. _objectTable.Remove(id); } } } return timeline; } ////// Cleans up the known timelines table by removing dead weak /// references. /// internal static void CleanKnownTimelinesTable() { lock (_debugLockObject) { Hashtable removeTable = new Hashtable(); // Identify dead references foreach (DictionaryEntry e in _objectTable) { WeakReference weakRef = (WeakReference) e.Value; if (weakRef.Target == null) { removeTable[e.Key] = weakRef; } } // Remove dead references foreach (DictionaryEntry e in removeTable) { _objectTable.Remove(e.Key); } } } #endif // DEBUG #endregion // Debugging instrumentation #region Data #region Event Handler Storage internal static readonly UncommonFieldEventHandlersStoreField = new UncommonField (); // Unique identifiers for each of the events defined on Timeline. // This is used as a key in the EventHandlerStore internal static readonly EventPrivateKey CurrentGlobalSpeedInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CurrentStateInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CurrentTimeInvalidatedKey = new EventPrivateKey(); internal static readonly EventPrivateKey CompletedKey = new EventPrivateKey(); internal static readonly EventPrivateKey RemoveRequestedKey = new EventPrivateKey(); #endregion // Event Handler Storage #region Debug data #if DEBUG internal int _debugIdentity; internal static int _nextIdentity; internal static Hashtable _objectTable = new Hashtable(); internal static object _debugLockObject = new object(); #endif // DEBUG #endregion // Debug data #endregion // Data #endregion // Internal implementation } } // 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
- HttpSessionStateWrapper.cs
- NavigateEvent.cs
- WebControlAdapter.cs
- TextRunTypographyProperties.cs
- TitleStyle.cs
- PrintEvent.cs
- InvokeMethodActivityDesigner.cs
- OleDbPropertySetGuid.cs
- VisualTransition.cs
- RedistVersionInfo.cs
- InputScopeAttribute.cs
- RawTextInputReport.cs
- ConstNode.cs
- DiscoveryVersionConverter.cs
- CreatingCookieEventArgs.cs
- HealthMonitoringSectionHelper.cs
- WebResourceAttribute.cs
- PointHitTestParameters.cs
- StateItem.cs
- HotSpotCollection.cs
- DocumentPage.cs
- SystemParameters.cs
- DataFormats.cs
- MULTI_QI.cs
- WindowsImpersonationContext.cs
- Vector.cs
- SynchronizedInputProviderWrapper.cs
- EntityClassGenerator.cs
- assemblycache.cs
- VisualBasicSettings.cs
- X509RecipientCertificateServiceElement.cs
- ISAPIApplicationHost.cs
- BaseTemplateBuildProvider.cs
- NativeMethodsCLR.cs
- EditingScope.cs
- EndEvent.cs
- DataListGeneralPage.cs
- Executor.cs
- PrtTicket_Base.cs
- SoapInteropTypes.cs
- DbgUtil.cs
- WrapPanel.cs
- ValidationHelper.cs
- SendActivityDesignerTheme.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- dbenumerator.cs
- HtmlTableCell.cs
- HttpProfileGroupBase.cs
- DataSourceXmlSubItemAttribute.cs
- PolyLineSegment.cs
- Constants.cs
- Drawing.cs
- CustomWebEventKey.cs
- SecurityDescriptor.cs
- ProfileManager.cs
- StackOverflowException.cs
- SamlSubject.cs
- TdsParameterSetter.cs
- ArrayList.cs
- FamilyTypefaceCollection.cs
- CommandLineParser.cs
- InterleavedZipPartStream.cs
- TabRenderer.cs
- UrlPropertyAttribute.cs
- PropertySegmentSerializationProvider.cs
- Documentation.cs
- ConfigurationSettings.cs
- NonceCache.cs
- ObjectDataSourceFilteringEventArgs.cs
- path.cs
- SurrogateChar.cs
- SmtpFailedRecipientsException.cs
- PreDigestedSignedInfo.cs
- XmlChildNodes.cs
- ScaleTransform.cs
- DataServiceQueryProvider.cs
- TableRow.cs
- ElapsedEventArgs.cs
- ClientSettingsProvider.cs
- UrlMappingsSection.cs
- AmbientProperties.cs
- XmlSchemaSimpleContent.cs
- SqlNode.cs
- TreeNodeCollection.cs
- FilteredDataSetHelper.cs
- SatelliteContractVersionAttribute.cs
- AxHostDesigner.cs
- ObjectMaterializedEventArgs.cs
- SchemaSetCompiler.cs
- EmbeddedMailObjectsCollection.cs
- ValidateNames.cs
- DescriptionAttribute.cs
- PerspectiveCamera.cs
- _FixedSizeReader.cs
- StateChangeEvent.cs
- PageParserFilter.cs
- URLIdentityPermission.cs
- WindowsListViewGroupHelper.cs
- MessageBox.cs
- PropertyTabChangedEvent.cs