WPF/Move-Control.ps1

function Move-Control {
    <#
    .Synopsis
        Moves a control to a location, and animates the transition
    .Description
        Moves a control to a fixed point on the screen, to another control's location, or to the location and size of the parent control.
        Also allows the control to be faded in or faded out
    .Example
        New-Button -show "Click me and I'll fade away" -On_Click {
            $this | Move-Control -fadeOut -duration ([Timespan]::FromMilliseconds(500))
        }
    .Parameter name
        The name of the control to move
    .Parameter control
        The real control to move
    .Parameter targetName
        The name of the target to move the control to
    .Parameter target
        The real control to move the target to
    .Parameter Width
        The width to resize the control to.
        If target or targetName is set, this will be replaced with the target's width.
    .Parameter Height
        The height to resize the control to.
        If target or targetName is set, this will be replaced with the target's height.
    .Parameter Top
        The new top location of the control
        If target or targetName is set, this will be replaced with the target's top.
    .Parameter Left
        The new left location of the control
        If target or targetName is set, this will be replaced with the target's left.
    .Parameter duration
        The amount of time the transition should take. If this is not set, then the transition will be immediate.
    .Parameter fadeIn
        If set, will fade in the opacity of the control
    .Parameter fadeOut
        If set, will fade out the opacity of the control
    .Parameter AccelerationRatio
        The AccelerationRatio used for all animation
    .Parameter DecelerationRatio
        The DeccelerationRatio used for all animation
    .Parameter autoScroll
        If set, will find the fist parent UI element containing this item and will scroll it to the upper left coordinates of the item.
    .Parameter On_Completed
        If set, will run the script block when the move is completed
    #>

    [CmdletBinding(DefaultParameterSetName="Name")]
    param(
        [Parameter(Mandatory=$true,
            ParameterSetName="Name",
            Position=0)]
        [string[]]
        $name,
        
        [Parameter(Mandatory=$true,
            ParameterSetName="Control",
            ValueFromPipeline=$true)]
        [Windows.UIElement]
        $control,
        
        [string]
        $targetName,
        
        [Windows.UIElement]
        $target,
        
        [Double]
        $Width,
        
        [Double]
        $Height,
        [Double]
        $Top,        
        
        [Double]
        $Left,
        
        [Timespan]$duration = [Timespan]"0:0:0.00",
        
        [Double]$AccelerationRatio,
        [Double]$DecelerationRatio,
        [ScriptBlock[]]$On_Completed = {},
        [switch]$fadeIn,
        [switch]$fadeOut,
        [switch]$autoScroll
    )
    begin {
        $controls = @()
    }
    process {
        switch ($psCmdlet.ParameterSetName) {
            Name {
                if ($window) {
                    foreach ($n in $name) {
                        $controls += ($window | Get-ChildControl $n)
                    }
                }
            }
            Control {                
                $controls += $control
            }
        }
    }
    end {
        if ($targetName) {
            $target = $window | Get-ChildControl $targetName
        }
                
        if ($target) {            
            $width = $target.ActualWidth            
            $height = $target.ActualHeight
            $top = $target.Top
            $left = $target.Left
        }
    
        $animationTemplate = @{
            AccelerationRatio = $AccelerationRatio
            DecelerationRatio = $DecelerationRatio
            Duration = $duration        
        }
        foreach ($c in $controls) {
            $dp = @{}
            $c.GetLocalValueEnumerator() | ForEach-Object {
                $value = $_
                switch ($_.Property.Name) {
                    Width { $dp.Width = $value.Property } 
                    Height { $dp.Height = $value.Property } 
                    Top { $dp.Top = $value.Property } 
                    Left { $dp.Left = $value.Property } 
                }
            }
            $widthProperty = $dp.Width
            if ($widthProperty -and 
                ($psBoundParameters.ContainsKey("Width") -or $psBoundParameters.Target -or $psBoundParameters.TargetName)) {                
                if ($width -ne ($c.GetValue($widthProperty))) {
                    if ($duration.TotalMilliseconds) {                        
                        
                        $widthChange = New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                            From = $c.GetValue($widthProperty)
                            To = $Width
                        } + $animationTemplate)

                        foreach ($oc in $On_Completed) {
                            $widthChange |Add-EventHandler -EventName "On_Completed" -Handler $oc
                        }
                        $on_Completed = $null
                        $c.BeginAnimation(
                            $widthProperty,
                            $WidthChange
                        )
                    } else {
                        $c.SetValue($widthProperty, $width)                    
                    }
                }
            }
            
            $HeightProperty = $dp.Height
            if ($HeightProperty -and
                ($psBoundParameters.ContainsKey("Height") -or $psBoundParameters.Target -or $psBoundParameters.TargetName)) {                
                if ($height -ne ($c.GetValue($HeightProperty))) {
                    if ($duration.TotalMilliseconds) {                        
                        $heightChange = New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                            From = $c.GetValue($heightProperty)
                            To = $height
                        } + $animationTemplate)
                        foreach ($oc in $On_Completed) {
                            $heightChange |Add-EventHandler -EventName "On_Completed" -Handler $oc
                        }
                        $on_Completed = $null
                        $c.BeginAnimation(
                            $HeightProperty,
                            $HeightChange
                        )
                    } else {
                        $c.SetValue($HeightProperty, $Height)
                    }
                }
            }
            $TopProperty = $dp.Top
            if ($TopProperty -and 
                ($psBoundParameters.ContainsKey("Top") -or $psBoundParameters.Target -or $psBoundParameters.TargetName)) {                
                if ($top -ne ($c.GetValue($topProperty))) {
                    if ($duration.TotalMilliseconds) {                
                        
                        $topChange = New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                            From = $c.GetValue($topProperty)
                            To = $top
                        } + $animationTemplate)
                        

                        foreach ($oc in $On_Completed) {
                            $topChange |Add-EventHandler -EventName "On_Completed" -Handler $oc
                        }
                        $on_Completed = $null

                        $c.BeginAnimation(
                            $TopProperty,
                            $TopChange
                        )
                    } else {
                        $c.SetValue($TopProperty, $Top)
                    }
                }
            }
            
            $LeftProperty = $dp.Left
            if ($LeftProperty -and 
                ($psBoundParameters.ContainsKey("Left") -or $psBoundParameters.Target -or $psBoundParameters.TargetName)) {                
                if ($left -ne ($c.GetValue($leftProperty))) {
                    if ($duration.TotalMilliseconds) {
                        
                        $leftChange = New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                            From = $c.GetValue($leftProperty)
                            To = $left
                        } + $animationTemplate)
                        foreach ($oc in $On_Completed) {
                            $leftChange|Add-EventHandler -EventName "On_Completed" -Handler $oc     
                        }
                        $on_Completed = $null

                        $c.BeginAnimation(
                            $LeftProperty,
                            $LeftChange
                        )
                    } else {
                        $c.SetValue($LeftProperty, $Left)
                    }
                }
            }
            
            if ($fadeIn) {
                $c.Visibility = "Visible"
                if ($duration.TotalMilliseconds) {
                    

                    $fadeChange= New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                        From = ($c.GetValue($c.GetType()::OpacityProperty))
                        To = 1
                    } + $animationTemplate)

                    foreach ($oc in $On_Completed) {
                        $fadeChange |Add-EventHandler -EventName "On_Completed" -Handler $oc     
                    }
                    $on_Completed = $null
                                        
                    $c.BeginAnimation(
                        $c.GetType()::OpacityProperty,
                        $fadeChange
                    )
                } else {
                    $c.SetValue($c.GetType()::OpacityProperty, [Double]1)
                }
            } else {
                if ($fadeOut) {
                    if ($duration.TotalMilliseconds) {
                        $guid = [GUID]::NewGuid().ToString()
                        $window.Resources.TemporaryControls."$guid" = $c
                        $hideScript = [ScriptBlock]::Create("
                            `$window.Resources.TemporaryControls.'$guid'.Visibility = 'Collapsed'
                            `$window.Resources.TemporaryControls.Remove('$guid')
                        "
)
                        $fadeChange = 

                         $fadeChange= New-Object System.Windows.Media.Animation.DoubleAnimation -Property (@{
                            From = ([Double]($c.GetValue($c.GetType()::OpacityProperty)))
                            To = ([Double]0)
                        } + $animationTemplate)
                        $fadeChange |Add-EventHandler -EventName "On_Completed" -Handler $hideScript
                            

                        $c.BeginAnimation(
                            $c.GetType()::OpacityProperty,
                            $fadeChange
                        )
                    } else {
                        $c.SetValue($c.GetType()::OpacityProperty, [Double]0)
                        $c.Visibility = "Collapsed"
                    }                    
                }
            }
            if ($autoScroll) {
                #If there's a scrollviewer, then scroll the scrollviewer
                $scrollViewer = $null
                $p = $c.Parent            
                while ($p) {
                    if ($p -is [Windows.Controls.ScrollViewer]) {
                        $scrollViewer = $p
                        break
                    }
                    $p = $p.Parent
                }
                if ($scrollViewer) {
                    if ($duration.TotalMilliseconds) {
                        $guid = [GUID]::NewGuid().ToString()
                        $window.Resources.TemporaryControls."$guid" = $c
                        $scrollViewerGuid = [GUID]::NewGuid().ToString()
                        $window.Resources.TemporaryControls."$scrollViewerGuid" = $scrollViewer                        
                        $scrollScript = [ScriptBlock]::Create("
                            `$scrollViewer = `$window.Resources.TemporaryControls.'$scrollViewerGuid'
                            `$c = `$window.Resources.TemporaryControls.'$guid'
                            `$p = `$c.TranslatePoint(
                                (New-Object Windows.Point 0,0),
                                `$scrollViewer)
                            `$scrollViewer.ScrollToVerticalOffset(`$p.Y)
                            `$scrollViewer.ScrollToHorizontalOffset(`$p.X)
                            `$window.Resources.TemporaryControls.Remove('$guid')
                            `$window.Resources.TemporaryControls.Remove('$scrollViewerGuid')
                        "
)
                        Register-PowerShellCommand `
                            -run -once -in $duration `
                            -scriptBlock $scrollScript                     
                    } else {
                        $p = $c.TranslatePoint(
                            (New-Object Windows.Point 0,0),
                            $scrollViewer)
                        $scrollViewer.ScrollToVerticalOffset($p.X)
                        $scrollViewer.ScrollToHorizontalOffset($p.Y)
                    }
                }
            }                            
        }
    }   
}