# encoding: utf-8
# api: powershell
# title: Sjöstrand
# description: wpftools is a tool for easy use of wpf
# version: 0.1
# type: function
# author: David
# license: CC0
# function: Get-WindowsClasses
# x-poshcode-id: 6316
# x-archived: 2016-04-24T06:47:14
# x-published: 2016-04-22T10:37:00
#
#
#Requires -Version 3
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type –AssemblyName WindowsBase
function Get-WindowsClasses
{
$exportedClasses = [System.Reflection.Assembly]::LoadWithPartialName('PresentationFramework').ExportedTypes
$exportedClasses += [System.Reflection.Assembly]::LoadWithPartialName('PresentationCore').ExportedTypes
$exportedControlClasses = $exportedClasses | Where-Object {$_.isclass -and $_.fullname -like "System.Windows.*"}
$controlClasses = @{}
foreach ($controlClass in $exportedControlClasses)
{
$controlClasses[$controlClass.Name] = $controlClass.FullName
}
$controlClasses
}
function Show-WpfWindow ([string]$XamlPath=".\MainWindow.xaml", [string]$HashTableName, [switch]$Dialog = $true)
{
if (!(Test-Path $XamlPath))
{
throw "Could not find file $XamlPath"
}
[xml]$xaml = Get-Content $XamlPath
$nsmgr = new-object system.xml.xmlnamespacemanager($xaml.nametable)
$nsmgr.AddNamespace("x",$xaml.DocumentElement.x)
$xaml.window.RemoveAttribute("x:Class")
$controlEvents = @{}
$controlClasses = Get-WindowsClasses
:outer foreach ($element in $xaml.SelectNodes('//*[@x:Name]', $nsmgr))
{
$name = $element.name
$typename = $controlClasses[$element.LocalName]
$type = $null
try { $type = [type]$typename } catch { Write-Debug "type $typename does not exist"; continue outer}
Write-Debug "$typeName`: $name"
foreach ($event in $type.GetEvents())
{
$attributeName = $event.Name
$attributeValue = $element.GetAttribute($attributeName)
if ($attributeValue -and (Test-Path "function:$attributeValue"))
{
Write-Debug "Found event: $attributeName - $attributeValue"
$controlEvents[$name] += @{$attributeName=(Get-Item "function:$attributeValue").ScriptBlock}
}
elseif (Test-Path "function:${name}_$attributeName")
{
Write-Debug "Found eventhandler $name_$attributeName"
$controlEvents[$name] += @{$attributeName=(Get-Item "function:${name}_$attributeName").ScriptBlock}
}
if ($AttributeValue)
{
$element.RemoveAttribute($attributeName)
}
}
}
$reader = New-Object System.Xml.XmlNodeReader($xaml)
$Window = [Windows.Markup.XamlReader]::Load( $reader )
if ($PSBoundParameters.ContainsKey("HashTableName"))
{
if (Test-Path "Variable:$HashTableName")
{
Remove-Variable $HashTableName
}
$HashTable = (New-Variable -scope 1 -name $HashTableName -value ([hashtable]::Synchronized(@{})) -PassThru -Option Constant).Value
}
foreach ($element in $xaml.SelectNodes('//*[@x:Name]', $nsmgr))
{
$name = $element.name
$control = $Window.FindName($name)
if ($control)
{
if ($PSBoundParameters.ContainsKey("HashTableName"))
{
$HashTable[$name] = $control
}
else
{
if (Test-Path "Variable:$name")
{
Remove-Variable $name
}
New-Variable -scope 1 -Name $name -Value $control -Option Constant -ErrorAction SilentlyContinue
}
}
}
foreach ($controlName in $controlEvents.Keys)
{
$control = $Window.FindName($controlName)
if (!$control)
{
continue
}
foreach ($eventName in $controlEvents[$controlName].Keys)
{
#$scriptBlock = [System.Management.Automation.ScriptBlock]::Create($controlEvents[$controlName][$eventName])
$scriptBlock = $controlEvents[$controlName][$eventName]
Write-Debug "Regestering event $controlname.${eventName}"
($control."add_$eventName").Invoke($scriptBlock)
}
}
if ($Dialog)
{
[void]$Window.ShowDialog()
}
else
{
[void]$Window.Show()
}
}
function Get-WpfSnippet ($XamlPath=".\MainWindow.xaml", [string]$HashTableName,
[parameter()]
[ValidateSet("None", "Normal", "High", "Full")]
[String[]]
$CommentDetail="Normal",
$CommentBorderLength = 85)
{
if ([System.Management.Automation.Runspaces.Runspace]::DefaultRunspace.apartmentstate -ne "STA")
{
throw "Generate-WpfSnippet must be run in a single threaded apartment. Start PowerShell with the -STA flag and rerun the script."
exit
}
[xml]$xaml = Get-Content $XamlPath
$nsmgr = new-object system.xml.xmlnamespacemanager($xaml.nametable)
$nsmgr.AddNamespace('x',$xaml.DocumentElement.x)
#$xaml.window.RemoveAttribute("x:Class")
if ($CommentDetail -ne 'None')
{
'#' * $CommentBorderLength
'# Controls:'
'#'
}
$controlEvents = @{}
$controlTypes = @{}
$controlClasses = Get-WindowsClasses
:outer foreach ($element in $xaml.SelectNodes('//*[@x:Name]', $nsmgr))
{
$name = $element.name
$typename = $controlClasses[$element.LocalName]
Write-Debug "$typeName`: $name"
$type = $null
if ($controlTypes.ContainsKey($typename))
{
$type = $controlTypes[$typename]
}
else
{
try { $type = [type]$typename } catch { Write-Debug "Unknown error getting type $typename"; continue outer}
$controlTypes[$typename] = $type
}
if ($CommentDetail -ne 'None')
{
if ($PSBoundParameters.ContainsKey("HashTableName"))
{
'# ${0}{1,-20} ({2})' -F $HashTableName,"['$name']",$typename
}
else
{
'# ${0,-20} ({1})' -F $name,$typename
}
}
foreach ($event in $type.GetEvents())
{
$attributeName = $event.Name
$attributeValue = $element.GetAttribute($attributeName)
if ($attributeValue)
{
Write-Debug "Found event handler: $attributeName - $attributeValue"
$controlEvents[$attributeValue] += @{$name=$attributeName}
#$element.RemoveAttribute($attributeName)
}
}
}
if ("High","Full" -contains $CommentDetail)
{
'#' * $CommentBorderLength
'# Types:'
'#'
foreach ($typename in $controlTypes.Keys)
{
"# $typename"
$str = '# Events:'
$count = 0
foreach ($eventName in ($controlTypes[$typename].GetEvents() | Select-Object -ExpandProperty Name))
{
if (!($count++ % 3))
{
$str += "`n# "
}
$str += "$eventName ".PadRight(30)
}
$str.Split("`n")
if ($CommentDetail -ne "Full")
{
continue
}
"# Properties:"
foreach ($Property in $controlTypes[$typename].GetProperties())
{
'# {0,-30} ({1})' -F $property.name,$property.propertyType.fullname
}
}
}
if ($CommentDetail -ne 'None')
{
'#'
'#' * $CommentBorderLength
''
}
'#Requires -Version 2'
'. .\wpftools.ps1'
''
'# Event handlers:'
''
foreach ($eventName in $controlEvents.Keys)
{
foreach ($controlName in $controlEvents[$eventName].Keys)
{
"# $controlName $($controlevents[$eventName][$controlName])"
}
"function $eventName"
'{'
'}'
''
}
if ($PSBoundParameters.ContainsKey("HashTableName"))
{
"Show-WpfWindow -XamlPath '$XamlPath' -HashTableName '$HashTableName'"
}
else
{
"Show-WpfWindow -XamlPath '$XamlPath'"
}
}