ListItems only show after window is resized - wpf

I create a window from PowerShell that contains a ListView. The ListView gets its items from ItemsSource with binding. The list gets filled without problem, but when all is done, the listviewitems are not shown. They are only shown when I resize the window.
Same goes if I run again, any new items are only shown after I resize the window.
XAML:
<ListView Grid.Column="0" Name="Lv1">
<ListView.View>
<GridView>
<GridViewColumn Header="N" DisplayMemberBinding="{Binding Name}" Width="200"/>
<GridViewColumn Header="I" DisplayMemberBinding="{Binding LastWriteTime}" Width="150"/>
</GridView>
</ListView.View>
</ListView>
PowerShell, I have tried with PSCustomObject, PSObject, hashtable, but same result:
$Something = { param( $syncHash )
# Gather stuff in $t
$syncHash.DataContext[4].Add( [pscustomobject]#{ Name = $t.Name; LastWriteTime = $t.LastWriteTime } )
}
$syncHash = [hashtable]::Synchronized(#{})
$syncHash.Window = [Windows.Markup.XamlReader]::Load( ( New-Object System.Xml.XmlNodeReader ( [xml]( Get-Content .\tt.xml ) ) ) )
$syncHash = [hashtable]::Synchronized(#{})
$Bindings = New-Object System.Collections.ArrayList
$Lv1Source = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
$Lv2Source = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
0.0, 0.0, "", 0.0, $Lv1Source, $Lv2Source | foreach { $syncHash.DataContext.Add( $_ ) }
$syncHash.Button.Add_Click( {
( [powershell]::Create().AddScript( $Something ).AddArgument( $syncHash ) ).BeginInvoke()
} )
$syncHash.Window.DataContext = $syncHash.DataContext
0..( $syncHash.DataContext.Count - 1 ) | foreach { [void]$Bindings.Add( ( New-Object System.Windows.Data.Binding -ArgumentList "[$_]" ) ) }
$Bindings | foreach { $_.Mode = [System.Windows.Data.BindingMode]::OneWay }
[void][System.Windows.Data.BindingOperations]::SetBinding( $syncHash.Lv1, [System.Windows.Controls.ListView]::ItemsSourceProperty, $Bindings[4] )
[void][System.Windows.Data.BindingOperations]::SetBinding( $syncHash.Lv2, [System.Windows.Controls.ListView]::ItemsSourceProperty, $Bindings[5] )
$syncHash.DataContext[4].Add( [pscustomobject]#{Name=$t.Name;LastWriteTime=$t.LastWriteTime } )

I found a solution to the problem thanks to the last post here, "When calling between runspaces we need to use the 'Dispatcher'".
In conclusion, the DataContext is updated through the syncHash, but in the scriptblock for the button-click, I need to use:
$syncHash.Window.Dispatcher.Invoke( [action] {
$syncHash.Lv1.Items.Refresh()
$syncHash.DataContext[5].Add( [pscustomobject]#{ Name = $syncHash.h[$syncHash.ti] ; LastWriteTime = ( Get-Date ) } )
} )

Related

Get clicked MenuItem header value from datagrid context menu in WPF/PowerShell

In a WPF DataGrid via PowerShell, I have added a context menu and MenuItems from an Array. I would like to get the header value of clicked MenuItem to handle the click event further. I had tried add_Click event to the MenuItem object but it does return any value. I'm looking for some ideas to get the Header value in this scenario (or) if there is any different better approach to achieve this goal. Thanks in advance.
[xml]$inputXML=#"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
Title="MainWindow" Height="275" Width="375">
<Window.InputBindings>
<KeyBinding x:Name="keyTest" Modifiers="Control" Key="N" Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>
<Grid>
<DataGrid x:Name="dg" Margin="5,5,0,0" Height="250" Width="350" ColumnWidth="Auto" AlternationCount="1" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell" Background="White" ClipboardCopyMode="IncludeHeader" >
<DataGrid.ContextMenu >
<ContextMenu x:Name="cxmenu" />
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
"#
[xml]$XAML = $inputXML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($reader)
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'x:Name')]]") | %{Set-Variable -Name "$($_.Name)" -Value $Window.FindName($_.Name)}
#sample data
$DataSet = New-Object System.Data.DataSet
$Table = $DataSet.Tables.Add("Table")
$Properties = #("Country","Capital","Population")
$Properties | foreach {
$Column = New-Object System.Data.DataColumn($_)
$Table.Columns.Add($Column)
}
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
#populate datagrid
$DataView = New-Object System.Data.DataView($Table)
$array = New-Object System.Collections.ArrayList
[void] $array.AddRange($DataView)
$dg.clear()
$dg.ItemsSource = $array
$dg.IsReadOnly = $true
#add MenuItem to context menu
$cxMenuitem = New-Object Windows.Controls.MenuItem
$header = ('Test1','Test2','Test3')
for ($i = 0; $i -le $header.Count -1; $i++)
{
$cxMenuitem.Header = [string]$header[$i]
$cxMenu.Items.Add($cxMenuitem.Header)
}
$cxMenuitem.Add_Click({
#Get the Header of the clicked MenuItem from Context Manu here for further handling
[System.Windows.MessageBox]::Show($cxMenu.Items)
})
#Display Form
$Window.ShowDialog() | Out-Null
You should be able to cast $args[0] to a MenuItem and access its Header property directly:
$cxMenuitem.Add_Click({
$sender = [System.Windows.Controls.MenuItem]$args[0]
# Use $sender.Header ...
})

WPF window not updating from PowerShell

I'm having trouble with having a WPF-window do continues update from PowerShell, and also not freeze.
The idea is that when I click the button, some function is to be run that updates the value for the progressbar. But which ever method or guide I use, I can't get it to work. The progressbar is being updated and is filled to 100% when the task is done. But during the operation, the window freezes. The only way I can have a window that is not freezing, is if I do a simple value addition in the updateblock. But I need to be able to run different functions and update the progressbar again and again.
What do I need to do to run a function or scriptblock from the Click-event so the window doesn't freeze and the progressbar updates?
PowerShell-code:
Add-Type -Assembly PresentationFramework
$syncHash = [hashtable]::Synchronized( #{} )
$syncHash.Counter = 0.0
$syncHash.Do = {
param ( $syncHash, $ToDo )
$rsR = [runspacefactory]::CreateRunspace()
$rsR.ApartmentState = "STA"
$rsR.ThreadOptions = "ReuseThread"
$rsR.Open()
$rsR.SessionStateProxy.SetVariable( "syncHash", $syncHash )
$c = [powershell]::Create().AddScript( $ToDo )
$c.Runspace = $rsR
$h = $c.BeginInvoke()
do { start-sleep -millisecond 10 } until ( $h.IsCompleted -eq $true )
$c.EndInvoke( $h )
$rsR.Close()
$rsR.Dispose()
}
$syncHash.Window = [Windows.Markup.XamlReader]::Load( ( New-Object System.Xml.XmlNodeReader ( [xml]( Get-Content .\tt.xml ) ) ) )
$syncHash.Button = $syncHash.Window.FindName( "Button" )
$syncHash.Progress = $syncHash.Window.FindName( "Progress" )
$Timer = New-Object System.Windows.Threading.DispatcherTimer
$Task = { 1..100 | % { start-sleep -millisecond 10; $syncHash.Counter = $_ } }
$syncHash.Button.Add_Click( { Something } )
$syncHash.Window.Add_SourceInitialized( {
$Timer.Start()
$Timer.Add_Tick( $UpdateBlock )
$Timer.Interval = [TimeSpan]"0:0:0.01"
} )
function Something
{
& $syncHash.Do $syncHash $Task
}
$UpdateBlock =`
{
$syncHash.Window.Resources["Progress"] = [double]$syncHash.Counter
$syncHash.Window.Resources["PbText"] = "$( $syncHash.Counter ) %"
}
[void]$syncHash.Window.ShowDialog()
XAML-code:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Topmost="True"
WindowStartupLocation="CenterScreen"
SizeToContent="WidthAndHeight">
<Window.Resources>
<system:Double x:Key="Progress">0.0</system:Double>
<system:String x:Key="PbText"></system:String>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click" Name="Button"/>
<Grid Grid.Row="1">
<ProgressBar Name="Progress" Minimum="0" Value="{DynamicResource Progress}" Width="230"/>
<TextBlock Text="{DynamicResource PbText}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
I finally found what to do. Hade to rethink some stuff, and removed the runspace functionality all together.
Thanks to binding, it all got simpler.
Here is what I came to, also added binding for maxvalue of the progressbar:
Add-Type -Assembly PresentationFramework
$syncHash = #{}
$syncHash.Window = [Windows.Markup.XamlReader]::Load( ( New-Object System.Xml.XmlNodeReader ( [xml]( Get-Content .\tt.xml ) ) ) )
$syncHash.Button = $syncHash.Window.FindName( "Button" )
$syncHash.Progress = $syncHash.Window.FindName( "Progress" )
$Something = { param( $d )
function SomethingElse { gci }
$d[1] = ( SomethingElse ).Count
[system.windows.messagebox]::show($d[1])
foreach ( $i in ( 1..$d[1] ) ) { Start-Sleep -MilliSeconds 300; $d[0] = [double]( ( $i/$d[1] ) * 100 ) }
}
$syncHash.Button.Add_Click( { ( [powershell]::Create().AddScript( $Something ).AddArgument( $DataContext ) ).BeginInvoke() } )
$DataContext = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
$DataContext.Add( 0.0 )
$DataContext.Add( 0.0 )
$syncHash.Progress.DataContext = $DataContext
$Binding = New-Object System.Windows.Data.Binding -ArgumentList "[0]"
$Binding.Mode = [System.Windows.Data.BindingMode]::OneWay
[void][System.Windows.Data.BindingOperations]::SetBinding( $syncHash.Progress, [System.Windows.Controls.ProgressBar]::ValueProperty, $Binding )
$Binding = New-Object System.Windows.Data.Binding -ArgumentList "[1]"
$Binding.Mode = [System.Windows.Data.BindingMode]::OneWay
[void][System.Windows.Data.BindingOperations]::SetBinding( $syncHash.Progress, [System.Windows.Controls.ProgressBar]::MaximumProperty, $Binding )
[void]$syncHash.Window.ShowDialog()

Powershell WPF ComboBox to update ListBox

I have a ComboBox that doesn't quite work.
It has 3 static selections for essentially sorting a long list of connection profiles plus a 'Select One' which is automatically selected.
No matter what selection I choose, nothing happens until I click on another selection. Now this is the interesting part. No matter what I choose next, the listbox populates with my previous selection.
<ComboBox Name="CBox" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" >
<ComboBoxItem Name="cbSelect" IsSelected="True">Select Profile</ComboBoxItem>
<ComboBoxItem Name="cbRemote">Remote</ComboBoxItem>
<ComboBoxItem Name="cbLab">Lab</ComboBoxItem>
<ComboBoxItem Name="cbTomcats">Tomcats</ComboBoxItem>
</ComboBox>
<ListBox Name="ListBox" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" />
$syncHash.CBox.Add_SelectionChanged({
If($syncHash.CBox.Text -eq "Select Profile")
{
$syncHash.ListBox.Items.Clear()
}
If($syncHash.CBox.Text -eq "Remote")
{
$syncHash.ListBox.Items.Clear()
$profiles = New-Object System.Collections.ArrayList
$profiles = (Get-ChildItem "C:\Profiles")
foreach ($profile in $profiles)
{
if ($profile -match 'Remote \-')
{
[void]$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
If($syncHash.CBox.Text -eq "Lab")
{
$syncHash.ListBox.Items.Clear()
$profiles = New-Object System.Collections.ArrayList
$profiles = (Get-ChildItem "C:\Profiles")
foreach ($profile in $profiles)
{
if ($profile -match 'Lab \-')
{
[void]$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
If($syncHash.CBox.SelectedItem -eq "Tomcats")
{
$syncHash.ListBox.Items.Clear()
$profiles = New-Object System.Collections.ArrayList
$profiles = (Get-ChildItem "C:\Profiles")
foreach ($profile in $profiles)
{
if ($profile -match 'Tomcats \-')
{
[void]$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
})
Final Solution using Rohin Sidharth's answer:
Add-Type -Path 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'
$Global:syncHash = [hashtable]::Synchronized(#{})
[xml]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="ComboBox Test" Height="500" Width="350">
<Grid Width="340" Height="470">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="0.1*" />
<RowDefinition Height="0.9*" />
</Grid.RowDefinitions>
<ComboBox Name="CBox" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" >
<ComboBoxItem Name="cbSelect" IsSelected="True">Select Profile</ComboBoxItem>
<ComboBoxItem Name="cbRemote">Remote</ComboBoxItem>
<ComboBoxItem Name="cbLab">Lab</ComboBoxItem>
<ComboBoxItem Name="cbTomcats">Tomcats</ComboBoxItem>
</ComboBox>
<ListBox Name="ListBox" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
[xml]$XAML = $xaml
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'Name')]]") | %{
$syncHash.Add($_.Name,$syncHash.Window.FindName($_.Name) )
}
function Get-Profiles
{
$profiles = (Get-ChildItem "C:\Profiles")
$syncHash.ListBox.Items.Clear()
If ($syncHash.CBox.SelectedIndex -eq 1)
{
foreach ($profile in $profiles)
{
if ($profile -match 'Remote \-')
{
$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
ElseIf ($syncHash.CBox.SelectedIndex -eq 2)
{
foreach ($profile in $profiles)
{
if ($profile -match 'Lab \-')
{
$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
ElseIf ($syncHash.CBox.SelectedIndex -eq 3)
{
foreach ($profile in $profiles)
{
if ($profile -match 'Tomcats \-')
{
$syncHash.ListBox.Items.Add($profile.BaseName)
}
}
}
}
$syncHash.CBox.Add_SelectionChanged({Get-Profiles})
$null = $syncHash.Window.ShowDialog()
$syncHash.Error = $Error
$Error
I haven't quite worked with WPF in powershell but in Winforms, I think to select an item on the combobox, you have to set the SelectedIndex property and not the text of the item. An index of 0 will select the 1st item on your dropdownlist

How can I add sorting by clicking on the column header in this GridView?

ipmo WPK
$ConnectionString = $ConnectionString = "Server=localhost;Integrated Security=True"
$conn = new-object System.Data.SQLClient.SQLConnection
$conn.ConnectionString = $ConnectionString
$conn.Open()
function Invoke-sql1
{
param( [string]$sql,
[System.Data.SQLClient.SQLConnection]$connection
)
$cmd = new-object System.Data.SQLClient.SQLCommand($sql,$connection)
$ds = New-Object system.Data.DataSet
$da = New-Object System.Data.SQLClient.SQLDataAdapter($cmd)
$da.fill($ds) | Out-Null
return $ds.tables[0]
}
function Show-Bockmarks ($conn) {
New-ListView -Name ListView -View {
New-GridView -AllowsColumnReorder -Columns {
New-GridViewColumn "title"
}
} -show -On_Loaded {
$ff_sql = #"
SELECT 'abc' title
union
SELECT 'xyz' title
union
SELECT 'efg' title
"#
$TableView = $window | Get-ChildControl ListView
$TableView.ItemsSource = #(Invoke-sql1 -sql $ff_sql -connection $conn)
}
}
Show-Bockmarks $conn
Edit:
I transformed the code to XAML
ipmo WPK
$ConnectionString = $ConnectionString = "Server=localhost;Integrated Security=True"
$conn = new-object System.Data.SQLClient.SQLConnection
$conn.ConnectionString = $ConnectionString
$conn.Open()
function Invoke-sql1
{
param( [string]$sql,
[System.Data.SQLClient.SQLConnection]$connection
)
$cmd = new-object System.Data.SQLClient.SQLCommand($sql,$connection)
$ds = New-Object system.Data.DataSet
$da = New-Object System.Data.SQLClient.SQLDataAdapter($cmd)
$da.fill($ds) | Out-Null
return $ds.tables[0]
}
function Show-Bockmarks ($conn) {
[xml] $xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" >
<ListView ItemsSource="{Binding Persons}"
IsSynchronizedWithCurrentItem="True"
Name="Listview">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="title"
DisplayMemberBinding="{Binding title}"
/>
<GridViewColumn Header="itemid"
DisplayMemberBinding="{Binding itemid}"
/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$ff_sql = #"
SELECT 'abc' title, 3 itemid
union
SELECT 'xyz' title, 2 itemid
union
SELECT 'efg' title, 1 itemid
"#
$TableView = $Form.FindName("Listview")
$TableView.ItemsSource = #(Invoke-sql1 -sql $ff_sql -connection $conn)
$Form.ShowDialog() #| out-null
}
Show-Bockmarks $conn
But when I added the lines proposed by Thomas Levesque
ipmo WPK
$ConnectionString = $ConnectionString = "Server=localhost;Integrated Security=True"
$conn = new-object System.Data.SQLClient.SQLConnection
$conn.ConnectionString = $ConnectionString
$conn.Open()
function Invoke-sql1
{
param( [string]$sql,
[System.Data.SQLClient.SQLConnection]$connection
)
$cmd = new-object System.Data.SQLClient.SQLCommand($sql,$connection)
$ds = New-Object system.Data.DataSet
$da = New-Object System.Data.SQLClient.SQLDataAdapter($cmd)
$da.fill($ds) | Out-Null
return $ds.tables[0]
}
function Show-Bockmarks ($conn) {
[xml] $xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:util="clr-namespace:TheNameSpace;assembly=TheAssembly"
Title="MainWindow" >
<ListView ItemsSource="{Binding Persons}"
IsSynchronizedWithCurrentItem="True"
util:GridViewSort.AutoSort="True"
Name="Listview">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="title"
DisplayMemberBinding="{Binding title}"
util:GridViewSort.PropertyName="title"
/>
<GridViewColumn Header="itemid"
DisplayMemberBinding="{Binding itemid}"
util:GridViewSort.PropertyName="itemid"
/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$ff_sql = #"
SELECT 'abc' title, 3 itemid
union
SELECT 'xyz' title, 2 itemid
union
SELECT 'efg' title, 1 itemid
"#
$TableView = $Form.FindName("Listview")
$TableView.ItemsSource = #(Invoke-sql1 -sql $ff_sql -connection $conn)
$Form.ShowDialog() #| out-null
}
Show-Bockmarks $conn
I get the error
Exception calling "Load" with "1" argument(s): "The property 'GridViewSort.AutoSort' does not exist in XML namespace 'clr-namespace:TheNameSpace;assembly=TheAssembly'. Line '0'
Position '0'."
I guess I have to register some assembly.
See this blog post (and this one) for a XAML solution
You can also use this solution in code using the GridViewSort.SetAutoSort and GridViewSort.SetPropertyName method. I don't know the Powershell syntax, but here it is in C#:
GridViewSort.SetAutoSort(TableView, true);
GridViewSort.SetPropertyName(TitleColumn, "title");

Can not add rows to WPF DataGrid in PowerShell

I am using DataGrid from "WPF Toolkit" from PowerShell. The problem is that I can't add new rows using GUI.
dialog.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WpfToolkit"
>
<Window.Resources>
<x:Array x:Key="people" Type="sys:Object" />
</Window.Resources>
<StackPanel>
<dg:DataGrid x:Name="_grid" ItemsSource="{DynamicResource people}" CanUserAddRows="True" AutoGenerateColumns="False">
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Header="First" Binding="{Binding First}"></dg:DataGridTextColumn>
<dg:DataGridTextColumn Header="Last" Binding="{Binding Last}"></dg:DataGridTextColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
<Button>test</Button>
</StackPanel>
</Window>
dialog.ps1
# Includes
Add-Type -AssemblyName PresentationFramework
[System.Reflection.Assembly]::LoadFrom("C:\Program Files\WPF Toolkit\v3.5.40320.1\WPFToolkit.dll")
# Helper methods
function LoadXaml
{
param($fileName)
[xml]$xaml = [IO.File]::ReadAllText($fileName)
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
[Windows.Markup.XamlReader]::Load( $reader )
}
# Load XAML
$form = LoadXaml('.\dialog.xaml')
#
$john = new-object PsObject
$john | Add-Member -MemberType NoteProperty -Name "First" -Value ("John")
$john | Add-Member -MemberType NoteProperty -Name "Last" -Value ("Smith")
$people = #( $john )
$form.Resources["people"] = $people
#
$form.ShowDialog()
run.bat
powershell -sta -file dialog.ps1
The problem seems to be in $people collection. I have tryed same code in C# and it worked, but the collection was defined this way:
List<Person> people = new List<Person>();
people.Add(new Person { First = "John", Last = "Smith" });
this.Resources["people"] = people;
Also tryed the Clr collection - did not work at all:
$people = New-Object "System.Collections.Generic.List``1[System.Object]"
$people.add($john)
Any ideas?
The final solution:
# Declare Person class
add-type #"
public class Person
{
public Person() {}
public string First { get; set; }
public string Last { get; set; }
}
"# -Language CsharpVersion3
# Make strongly-typed collection
[System.Collections.ArrayList] $people = New-Object "System.Collections.ArrayList"
#
$john = new-object Person
$john.First = "John"
$john.Last = "Smith"
$people.add($john)
$form.Resources["people"] = $people
[System.Collections.ArrayList] $people = New-Object "System.Collections.ArrayList"
If you must pass arguments, you should make them strongly-typed,
so that PowerShell doesn't wrap it as a PsObject.
Link no longer works

Resources