WPF/Set-Property.ps1

function Set-Property
{
    <#
    .Synopsis
        Sets properties on an object or subscribes to events
    .Description
        Set-Property is used by each parameter in the automatically generated
        controls in ShowUI.
    .Parameter InputObject
        The object to set properties on
    .Parameter Hashtable
        A Hashtable contains properties to set.
        The key is the name of the property on an object, or "On_" + the name
        of an event you can subscribe to (i.e. On_Loaded).
        The value can either be a literal value (such as a string), a block of XAML,
        or a script block that produces the value that needs to be set.
    .Example
        $window = New-Window
        $window | Set-Property @{Width=100;Height={200}}
        $window | show-Window
    #>

    param(    
    [Parameter(ValueFromPipeline=$true)]    
    [Object[]]$inputObject,
    
    [Parameter(Position=0)] 
    [Hashtable]$property,
    
    [switch]$AllowXaml,
    
    [switch]$doNotAutoCreateLabel,
    
    [Switch]$PassThru
    )
       
    process {
        foreach($object in $inputObject) {
            $inAsJob  = $host.Name -eq 'Default Host'
            if ($object.GetValue -and 
                ($object.GetValue([ShowUI.ShowUISetting]::StyleNameProperty))) {
                # Since Set-Property will be called by Set-UIStyle, make sure to check the callstack
                # rather than infinitely recurse
                $styleName = $object.GetValue([ShowUI.ShowUISetting]::StyleNameProperty)
               

                if ($styleName) {
                    $setUiStyleInCallStack = foreach ($_ in (Get-PSCallStack)) { 
                        if ($_.Command -eq 'Set-UIStyle') { $_ }
                    }
                    if (-not $setUiStyleInCallStack) {
                        Set-UIStyle -Visual $object -StyleName $StyleName 
                    }
                } 
            }
                
            if ($property) {
                # Write-Verbose "Setting $($property.Keys -join ',') on $object"
                $p = $property
                foreach ($k in $p.Keys) {
                    $realKey = $k
                    if ($k.StartsWith("On_")) {
                        $realKey = $k.Substring(3)
                    }

                    if ($object.GetType().GetEvent($realKey)) {
                        # It's an Event!
                        foreach ($sb in $p[$k]) {
                            Add-EventHandler $object $realKey $sb
                        } 
                        continue
                    }
                    
                    $realItem  = $object.psObject.Members[$realKey]
                    if (-not $realItem) { 
                        continue 
                    }

                    $itemName = $realItem.Name
                    if ($realItem.MemberType -eq 'Property') {
                        if ($realItem.Value -is [Collections.IList]) {
                            $v = $p[$realKey]
                            # Write-Host "$itemName is collection on $object " -fore cyan -nonewline
                            $collection = $object.$itemName
                            if (-not $v) { continue } 
                            if ($v -is [ScriptBlock]) { 
                                if ($inAsJob) {
                                    $v = . ([ScriptBlock]::Create($v))
                                } else {
                                    $v = . $v
                                }
                            }
                            if (-not $v) { continue } 

                            foreach ($ri in $v) {
                                # Write-Host "`n`tAdding $ri to $object.$itemName" -fore cyan -nonewline
                                $null = $collection.Add($ri)
                                trap [Management.Automation.PSInvalidCastException] {
                                    $label = New-Label $ri
                                    $null = $collection.Add($label)
                                    continue
                                }
                            }
                            # Write-Host
                        } else {
                            $v = $p[$realKey]
                            if ($v -is [ScriptBlock]) {
                                if ($inAsJob) {
                                    $v = . ([ScriptBlock]::Create($v))
                                } else {
                                    $v = . $v
                                }
                            }

                            if ($allowXaml) {
                                $xaml = ConvertTo-Xaml $v
                                if ($xaml) {
                                    try {
                                        $rv = [Windows.Markup.XamlReader]::Parse($xaml)
                                        if ($rv) { $v = $rv } 
                                    }
                                    catch {
                                        Write-Debug ($_ | Out-String)
                                    }
                                }
                            }

                            if($debugPreference -ne 'SilentlyContinue') {
                                Write-Debug "Control: $($object.GetType().FullName)"
                                Write-Debug "Type: $(@($v)[0].GetType().FullName)"
                                Write-debug "Property: $($realItem.TypeNameOfValue)"
                            }

                            # Two Special cases: Templates and Bindings
                            if([System.Windows.FrameworkTemplate].IsAssignableFrom( $realItem.TypeNameOfValue -as [Type]) -and 
                               $v -isnot [System.Windows.FrameworkTemplate]) {
                                if($debugPreference -ne 'SilentlyContinue') {
                                    Write-Debug "TEMPLATING: $object" -fore Yellow
                                }
                                $Template = $v | ConvertTo-DataTemplate -TemplateType ( $realItem.TypeNameOfValue -as [Type])
                                if($debugPreference -ne 'SilentlyContinue') {
                                    Write-Debug "TEMPLATING: $([System.Windows.Markup.XamlWriter]::Save( $Template ))" -fore Yellow
                                }
                                $object.$itemName = $Template

                            } elseif(@($v)[0] -is [System.Windows.Data.Binding] -and 
                                    (($realItem.TypeNameOfValue -eq "System.Object") -or 
                                    !($realItem.TypeNameOfValue -as [Type]).IsAssignableFrom([System.Windows.Data.BindingBase]))
                            ) {
                                $Binding = @($v)[0];
                                if($debugPreference -ne 'SilentlyContinue') {
                                    Write-Debug "BINDING: $($object.GetType()::"${realKey}Property")" -fore Green
                                }

                                if(!$Binding.Source -and !$Binding.ElementName) {
                                    $Binding.Source = $object.DataContext
                                }
                                if($object.GetType()::"${realKey}Property" -is [Windows.DependencyProperty]) {
                                    try {
                                        # $object.Resources.Clear()
                                        $null = $object.SetBinding( ($object.GetType()::"${realKey}Property"), $Binding )
                                    } catch {
                                        Write-Debug "Nope, was not able to set it." -fore Red
                                        Write-Debug $_ -fore Red
                                        Write-Debug $this -fore DarkRed
                                    }
                                } else {
                                    $object.$itemName = $v
                                }
                            } else {
                                $object.$itemName = $v
                            }
                        }
                    } elseif ($realItem.MemberType -eq 'Method') {
                        $object."$($itemName)".Invoke(@($p[$realKey]))
                    }
                }
            }
            
            if ($passThru) {
                $object
            }
        }
    }
}