| File: System\Windows\Input\Manipulations\InertiaExpansionBehavior2D.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\System.Windows.Input.Manipulations\System.Windows.Input.Manipulations.csproj (System.Windows.Input.Manipulations) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Windows.Input.Manipulations { /// <summary> /// Describes desired expansion behavior of an inertia processor. /// </summary> public sealed class InertiaExpansionBehavior2D : InertiaParameters2D { private const string initialRadiusName = "InitialRadius"; private const string desiredDecelerationName = "DesiredDeceleration"; private const string desiredExpansionXName = "DesiredExpansionX"; private const string desiredExpansionYName = "DesiredExpansionY"; private const string initialVelocityXName = "InitialVelocityX"; private const string initialVelocityYName = "InitialVelocityY"; private float initialRadius = 1; private float desiredDeceleration = float.NaN; private float desiredExpansionX = float.NaN; private float desiredExpansionY = float.NaN; private float initialVelocityX = float.NaN; private float initialVelocityY = float.NaN; /// <summary> /// Gets or sets the initial average radius, in coordinate units. /// </summary> /// <remarks> /// <para> /// This property is used by the inertia processor to calculate the scale factor for an element /// that is expanding. /// </para> /// <para> /// For instance, if the /// <strong><see cref="InitialVelocityX"/></strong> and <strong><see cref="InitialVelocityY"/></strong> /// properties are set to 3.75, this informs the inertia processor that the starting expansion velocity is 3.75 /// coordinate units per millisecond along both axes (expansion must be proportional). /// </para> /// <para> /// The scale factor associated with this rate of expansion depends upon the size of the element /// that is expanding. For a small element, this expansion velocity represents a larger scale factor /// than for a large element. You inform the inertia processor of the element size by setting the /// <strong>InitialRadius</strong> property. /// </para> /// <para>The default value for the <strong>InitialRadius</strong> property is 1.0.</para> /// <para>Valid values are any finite number greater than or equal to 1.0.</para> /// </remarks> public float InitialRadius { get { return this.initialRadius; } set { CheckRadius(value, initialRadiusName); ProtectedChangeProperty( () => value == this.initialRadius, () => this.initialRadius = value, initialRadiusName); } } /// <summary> /// Gets or sets the desired expansion deceleration, in coordinate units /// per millisecond squared. /// </summary> /// <remarks> /// <para> /// This property value is mutually exclusive with the /// <strong><see cref="DesiredExpansionX"/></strong> /// and /// <strong><see cref="DesiredExpansionY"/></strong> properties; /// setting this property will set /// <strong>DesiredExpansionX</strong> /// and /// <strong>DesiredExpansionY</strong> to <strong>NaN</strong>. /// </para> /// <para> /// The default value for this property is <strong>NaN</strong>. /// </para> /// <para> /// This property cannot be set while the inertia processor is running; /// otherwise, an exception is thrown. /// </para> /// </remarks> public float DesiredDeceleration { get { return this.desiredDeceleration; } set { Validations.CheckFiniteNonNegative(value, desiredDecelerationName); ProtectedChangeProperty( () => value == this.desiredDeceleration, () => { this.desiredDeceleration = value; this.desiredExpansionX = this.desiredExpansionY = float.NaN; }, desiredDecelerationName); } } /// <summary> /// Gets or sets the desired expansion along the x-axis, in coordinate units. /// </summary> /// <remarks> /// <para> /// Expansion must be proportional. The value of this property must equal the value of the /// <strong><see cref="DesiredExpansionY"/></strong> property when the inertia processor starts; /// otherwise an exception is thrown. /// </para> /// <para> /// This property value is mutually exclusive with the /// <strong><see cref="DesiredDeceleration"/></strong> property; /// setting this property will set /// <strong>DesiredDeceleration</strong> to <strong>NaN</strong>. /// </para> /// <para> /// The default value for this property is <strong>NaN</strong>. /// </para> /// <para> /// <strong>DesiredExpansionX</strong> must be a finite, non-negative number. /// The rate of expansion is determined by the /// <strong><see cref="InitialVelocityX"/></strong> property. /// </para> /// <para> /// This property cannot be set while the inertia processor is running; /// otherwise, an exception is thrown. /// </para> /// </remarks> public float DesiredExpansionX { get { return this.desiredExpansionX; } set { Validations.CheckFiniteNonNegative(value, desiredExpansionXName); ProtectedChangeProperty( () => (value == this.desiredExpansionX), () => { this.desiredExpansionX = value; this.desiredDeceleration = float.NaN; }, desiredExpansionXName); } } /// <summary> /// Gets or sets the desired expansion along the y-axis, in coordinate units. /// </summary> /// <remarks> /// <para> /// Expansion must be proportional. The value of this property must equal the value of the /// <strong><see cref="DesiredExpansionX"/></strong> property when the inertia processor starts; /// otherwise an exception is thrown. /// </para> /// <para> /// This property value is mutually exclusive with the /// <strong><see cref="DesiredDeceleration"/></strong> property; /// setting this property will set /// <strong>DesiredDeceleration</strong> to <strong>NaN</strong>. /// </para> /// <para> /// The default value for this property is <strong>NaN</strong>. /// </para> /// <para> /// <strong>DesiredExpansionY</strong> must be a finite, non-negative number. /// The rate of expansion is determined by the /// <strong><see cref="InitialVelocityY"/></strong> property. /// </para> /// <para> /// This property cannot be set while the inertia processor is running; /// otherwise, an exception is thrown. /// </para> /// </remarks> public float DesiredExpansionY { get { return this.desiredExpansionY; } set { Validations.CheckFiniteNonNegative(value, desiredExpansionYName); ProtectedChangeProperty( () => (value == this.desiredExpansionY), () => { this.desiredExpansionY = value; this.desiredDeceleration = float.NaN; }, desiredExpansionYName); } } /// <summary> /// Gets or sets the initial expansion velocity along the x-axis, in coordinate /// units per millisecond. /// </summary> /// <remarks> /// <para> /// Expansion must be proportional. The value of this property must equal the value of the /// <strong><see cref="InitialVelocityY"/></strong> property when the inertia processor starts; /// otherwise an exception is thrown. /// </para> /// <para> /// The default value for this property is <strong>NaN</strong>. /// Leaving this property and <strong>InitialVelocityY</strong> unchanged from the default or /// setting this property and <strong>InitialVelocityY</strong> to zero (0) /// will disable expansion inertia. /// </para> /// <para> /// This property cannot be set while the inertia processor is running; /// otherwise, an exception is thrown. /// </para> /// </remarks> public float InitialVelocityX { get { return this.initialVelocityX; } set { Validations.CheckFinite(value, initialVelocityXName); ProtectedChangeProperty( () => value == this.initialVelocityX, () => this.initialVelocityX = value, initialVelocityXName); } } /// <summary> /// Gets or sets the initial expansion velocity along the y-axis, in coordinate /// units per millisecond. /// </summary> /// <remarks> /// <para> /// Expansion must be proportional. The value of this property must equal the value of the /// <strong><see cref="InitialVelocityX"/></strong> property when the inertia processor starts; /// otherwise an exception is thrown. /// </para> /// <para> /// The default value for this property is <strong>NaN</strong>. /// Leaving this property and <strong>InitialVelocityX</strong> unchanged from the default or /// setting this property and <strong>InitialVelocityX</strong> to zero (0) /// will disable expansion inertia. /// </para> /// <para> /// This property cannot be set while the inertia processor is running; /// otherwise, an exception is thrown. /// </para> /// </remarks> public float InitialVelocityY { get { return this.initialVelocityY; } set { Validations.CheckFinite(value, initialVelocityYName); ProtectedChangeProperty( () => value == this.initialVelocityY, () => this.initialVelocityY = value, initialVelocityYName); } } /// <summary> /// This is called when the inertia processor is about to start processing. /// It checks to make sure that the behavior is in a valid state. There are /// two possible valid states: /// /// 1. Initial velocity is NaN, in which case expansion inertia will not /// occur. Desired deceleration and expansion values are ignored. /// /// 2. Initial velocity is set to something other than NaN, which means /// that rotation inertia will occur. In this case, either the /// desired deceleration or rotation values must be set. Also, /// the desired X and Y expansion components (velocities, and /// desired expansions if set) must equal each other. /// </summary> internal void CheckValid() { if (float.IsNaN(this.initialVelocityX) && float.IsNaN(this.initialVelocityY)) { // Velocity is unspecified, so no inertia will occur. This is // a valid state. return; } // X and Y components must match. if (this.initialVelocityX != this.initialVelocityY) { throw Exceptions.OnlyProportionalExpansionSupported( SubpropertyName(initialVelocityXName), SubpropertyName(initialVelocityYName)); } if (!float.IsNaN(this.desiredExpansionX) && !float.IsNaN(this.desiredExpansionY) && (this.desiredExpansionX != this.desiredExpansionY)) { throw Exceptions.OnlyProportionalExpansionSupported( SubpropertyName(desiredExpansionXName), SubpropertyName(desiredExpansionYName)); } // Must specify either deceleration or desired expansion. if (float.IsNaN(this.desiredDeceleration) && (float.IsNaN(this.desiredExpansionX) || float.IsNaN(this.desiredExpansionY))) { throw Exceptions.InertiaParametersUnspecified1and2( SubpropertyName(desiredDecelerationName), SubpropertyName(desiredExpansionXName), SubpropertyName(desiredExpansionYName)); } } private static string SubpropertyName(string paramName) { return "ExpansionBehavior." + paramName; } /// <summary> /// Checks if the given value is valid radius. /// </summary> /// <param name="value"></param> /// <param name="paramName"></param> private static void CheckRadius(float value, string paramName) { if (value < 1 || double.IsInfinity(value) || double.IsNaN(value)) { throw Exceptions.IllegialInertiaRadius(paramName, value); } } } }