Skip to content

Instantly share code, notes, and snippets.

@kewalaka
Created November 22, 2020 00:20
Show Gist options
  • Save kewalaka/0dea5e546d7cbff3a6b8e6b1cc753e0a to your computer and use it in GitHub Desktop.
Save kewalaka/0dea5e546d7cbff3a6b8e6b1cc753e0a to your computer and use it in GitHub Desktop.
WPF databinding in Powershell with nested PS custom objects - not working
#-------------------------------------------------------------#
#----Initial Declarations-------------------------------------#
#-------------------------------------------------------------#
Add-Type -AssemblyName PresentationCore, PresentationFramework
$Xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Width="800" Height="300" Name="khsdijy0ho5al">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="Update" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="updateButton"/>
<Button Content="Update Async" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="updateButtonASync"/>
<Button Content="Refresh" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="6" Grid.Row="0" Grid.Column="0" Name="refreshButton"/>
</StackPanel>
<DataGrid Grid.Row="1" Name="observableDataGrid" IsReadOnly="True" Margin="6" ItemsSource="{Binding serverList}" SelectedItem="{Binding selectedServer}">
</DataGrid>
</Grid>
</Window>
"@
#-------------------------------------------------------------#
#----Control Event Handlers-----------------------------------#
#-------------------------------------------------------------#
#Write your code here
function UpdateButton
{
$State.selectedServer.Status = (Get-Random | Out-String)
#$observableDataGrid.Items.Refresh()
}
function UpdateButtonAsync
{
Async {
$State.selectedServer.Status = (Get-Random | Out-String)
}
}
function Refresh
{
$observableDataGrid.Items.Refresh()
}
function OnLoad
{
$results = New-Object 'System.Collections.ObjectModel.ObservableCollection[System.Object]'
$results.Add([PSCustomObject]@{
"ServerInstance" = "MyServer"
"targetAccount" = "svcAccount"
"isEverythingDone" = $false
"Status" = ""
})
$observableDataGrid.itemsSource = $results
}
#endregion
#-------------------------------------------------------------#
#----Script Execution-----------------------------------------#
#-------------------------------------------------------------#
$Window = [Windows.Markup.XamlReader]::Parse($Xaml)
[xml]$xml = $Xaml
$xml.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name $_.Name -Value $Window.FindName($_.Name) }
$khsdijy0ho5al.Add_Loaded({OnLoad $this $_})
$updateButton.Add_Click({UpdateButton $this $_})
$updateButtonASync.Add_Click({UpdateButtonASync $this $_})
$refreshButton.Add_Click({Refresh $this $_})
$State = [PSCustomObject]@{}
Function Set-Binding {
Param($Target,$Property,$Index,$Name)
$Binding = New-Object System.Windows.Data.Binding
$Binding.Path = "["+$Index+"]"
$Binding.Mode = [System.Windows.Data.BindingMode]::TwoWay
[void]$Target.SetBinding($Property,$Binding)
}
function FillDataContext($props){
For ($i=0; $i -lt $props.Length; $i++) {
$prop = $props[$i]
$DataContext.Add($DataObject."$prop")
$getter = [scriptblock]::Create("return `$DataContext['$i']")
$setter = [scriptblock]::Create("param(`$val) return `$DataContext['$i']=`$val")
$State | Add-Member -Name $prop -MemberType ScriptProperty -Value $getter -SecondValue $setter
}
}
$DataObject = ConvertFrom-Json @"
{
"serverList" : [{
"ServerInstance" : "",
"targetAccount" : "",
"isEverythingDone" : "",
"Status": ""
}],
"selectedServer":""
}
"@
$DataContext = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
FillDataContext @("serverList","selectedServer")
$Window.DataContext = $DataContext
Set-Binding -Target $observableDataGrid -Property $([System.Windows.Controls.DataGrid]::ItemsSourceProperty) -Index 0 -Name "serverList"
Set-Binding -Target $observableDataGrid -Property $([System.Windows.Controls.DataGrid]::SelectedItemProperty) -Index 1 -Name "selectedServer"
$Global:SyncHash = [HashTable]::Synchronized(@{})
$Jobs = [System.Collections.ArrayList]::Synchronized([System.Collections.ArrayList]::new())
$initialSessionState = [initialsessionstate]::CreateDefault()
Function Start-RunspaceTask
{
[CmdletBinding()]
Param([Parameter(Mandatory=$True,Position=0)][ScriptBlock]$ScriptBlock,
[Parameter(Mandatory=$True,Position=1)][PSObject[]]$ProxyVars)
$Runspace = [RunspaceFactory]::CreateRunspace($InitialSessionState)
$Runspace.ApartmentState = 'STA'
$Runspace.ThreadOptions = 'ReuseThread'
$Runspace.Open()
ForEach($Var in $ProxyVars){$Runspace.SessionStateProxy.SetVariable($Var.Name, $Var.Variable)}
$Thread = [PowerShell]::Create('NewRunspace')
$Thread.AddScript($ScriptBlock) | Out-Null
$Thread.Runspace = $Runspace
[Void]$Jobs.Add([PSObject]@{ PowerShell = $Thread ; Runspace = $Thread.BeginInvoke() })
}
$JobCleanupScript = {
Do
{
ForEach($Job in $Jobs)
{
If($Job.Runspace.IsCompleted)
{
[Void]$Job.Powershell.EndInvoke($Job.Runspace)
$Job.PowerShell.Runspace.Close()
$Job.PowerShell.Runspace.Dispose()
$Runspace.Powershell.Dispose()
$Jobs.Remove($Runspace)
}
}
Start-Sleep -Seconds 1
}
While ($SyncHash.CleanupJobs)
}
Get-ChildItem Function: | Where-Object {$_.name -notlike "*:*"} | select name -ExpandProperty name |
ForEach-Object {
$Definition = Get-Content "function:$_" -ErrorAction Stop
$SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList "$_", $Definition
$InitialSessionState.Commands.Add($SessionStateFunction)
}
$Window.Add_Closed({
Write-Verbose 'Halt runspace cleanup job processing'
$SyncHash.CleanupJobs = $False
})
$SyncHash.CleanupJobs = $True
function Async($scriptBlock){ Start-RunspaceTask $scriptBlock @([PSObject]@{ Name='DataContext' ; Variable=$DataContext},[PSObject]@{Name="State"; Variable=$State})}
Start-RunspaceTask $JobCleanupScript @([PSObject]@{ Name='Jobs' ; Variable=$Jobs })
$Window.ShowDialog()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment