How to use XAML / WPF in PowerShell, how do I populate a list?

I found some excellent topics here, but can't find the answer. I am creating a GUI using Visual Studio and copying / pasting XAML into PowerShell. I know that I have to do this in C #, but since my knowledge is not there yet, this is pure PowerShell for me.

So, I have my GUI, but I can’t fill in my data fields. Doing other things, such as text fields, was feasible, but I can't get this listview / data table to fill in the values.

enter image description here

At this point, the connection to Azure is removed until I can solve this problem by adding items to my list.

Xaml to draw my form

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework') [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" xmlns:local="clr-namespace:Azure" Title="Azure Accelerator" Height="300" Width="315"> <Grid Margin="0,0,174,0"> <Image Name="image" HorizontalAlignment="Left" Height="46" Margin="10,10,-97,0" VerticalAlignment="Top" Width="210" Source="C:\Users\stephen\Dropbox\My Code\Powershell\WPF\mslogo.png"/> <TextBlock Name="textBlock" HorizontalAlignment="Left" Height="21" Margin="10,61,-140,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="248" Text="VM PickerUse"/> <Button Name="btnOK" Content="OK" HorizontalAlignment="Left" Margin="217,268,-160,0" VerticalAlignment="Top" Width="75" Height="23"/> <Button Name="btnExit" Content="Cancel" HorizontalAlignment="Left" Margin="12,268,0,0" VerticalAlignment="Top" Width="75" Height="23"/> <ListView Name="listView" HorizontalAlignment="Left" Height="108" Margin="12,107,-140,0" VerticalAlignment="Top" Width="246"> <ListView.View> <GridView> <GridViewColumn Header="VMName" DisplayMemberBinding ="{Binding VMName}"/> <GridViewColumn Header="Status" DisplayMemberBinding ="{Binding Status}"/> <GridViewColumn Header="Other"/> </GridView> </ListView.View> </ListView> </Grid> </Window> '@ 

Load XAML into memory / create objects

 #Read XAML $reader=(New-Object System.Xml.XmlNodeReader $xaml) try{$Form=[Windows.Markup.XamlReader]::Load( $reader )} catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."} #=========================================================================== # Store Form Objects In PowerShell #=========================================================================== $xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name "VMpick$($_.Name)" -Value $Form.FindName($_.Name)} 

Where I probably need help

 #Try to setup a dummy entry $vmpicklistView.items.Add( @{'VMName'='1';Status="AccessDenied";'Other'='1'}) #=========================================================================== # Shows the form #=========================================================================== $Form.ShowDialog() | out-null 

As you can see from my screenshot, when I added the binding to the columns (which, as I thought, instantiated the columns and allowed me to insert values ​​for them ... nope), they no longer update when I try to add a new item. However, the Other column, to which I did not apply the binding, at least shows someput, but it does not list Collection correctly, as if it is trying to display the entire hash table.

So my last question is how to add items to the list?

+6
source share
3 answers

Ok, I understood the answer. It turns out that when I used .Add, I had to specify a custom PowerShell object as my overload, and not just a hash table, as I did before. When I changed my code to the following:

 #Add DisplayMemberBindings for all columns <GridViewColumn Header="VMName" DisplayMemberBinding ="{Binding VMName}"/> <GridViewColumn Header="Status" DisplayMemberBinding ="{Binding Status}"/> <GridViewColumn Header="Other" DisplayMemberBinding ="{Binding Other}"/> 

And then change my Add statement:

 $vmpicklistView.items.Add([pscustomobject]@{'VMName'='1';Status="Access Denied";Other="Yes"}) 

I can fill in my fields, for example

 #Make Dummy Entries 1..15 | % { if ($_ % 2){$vmpicklistView.items.Add([pscustomobject]@{'VMName'="VM_$($_)";Status="Online";Other="Yes"})} else{$vmpicklistView.items.Add([pscustomobject]@{'VMName'="VM_$($_)";Status="Access Denied";Other="Yes"})} } 

enter image description here

Why did I have to do this?

Here is my interpretation of why this was necessary. Custom PowerShell objects provide an object with Named Values ​​that I can wrest with bindings, while a hash table is a collection of key / value pairs that are not suitable for this purpose.

I hope this answer helped everyone who was at an impasse like me!

+6
source

WPF is typically used to bind to the properties of a viewmodel, and not to dictionary or hash tables. There is syntax for binding to dictionary words that would make GridViewColumn bindings look like:

 <GridViewColumn Header="VMName" DisplayMemberBinding ="{Binding [VMName]}"/> <GridViewColumn Header="Status" DisplayMemberBinding ="{Binding [Status]}"/> 

Note the use of square brackets to indicate that the value comes from the indexer.

Regarding why the column β€œOther” is displayed as β€œ(Collection)”, I believe that the default binding will just show the object, and WPF should display dictionaries and hash tables as β€œ(Collection)”

Try adding a similar binding for Other:

 <GridViewColumn Header="Other" DisplayMemberBinding ="{Binding [Other]}"/> 
+2
source

There is a much simpler way to do this.

Say you have a setup similar to the previous question

 <ListView Name="Collections"> <ListView.View> <GridView> <GridViewColumn Header="Collection Name" DisplayMemberBinding="{Binding CollectionName}" /> <GridViewColumn Header="Collection Count" DisplayMemberBinding="{Binding CollectionCount}" /> </GridView> </ListView.View> </ListView> 

and in Powershell you get a list of objects from some provider (in this case, ConfigurationManager)

 $DCs = Get-CMDeviceCollection | ? { $_.CollectionRules.RuleName -contains "OU Query" } 

Now this out of the box has properties that do not match my DisplayMemberBindings, so we need to create a collection of objects that do this

 $BindableDCs = $DCs | Select-Object -Property @{Name='CollectionName';Expression={$_.Name}}, @{Name='CollectionCount';Expression={$_.MemberCount}} 

Now (assuming the code loads XAML and detects named elements and puts them in powershell variables)

 $Collections.ItemsSource = $BindableDCs 

Done.

Or if you want to do it in one way liner powershell

 $Collections.ItemsSource = Get-CMDeviceCollection | ? { $_.CollectionRules.RuleName -contains "OU Query" } | Select-Object -Property @{Name='CollectionName';Expression={$_.Name}}, @{Name='CollectionCount';Expression={$_.MemberCount}} 
0
source

Source: https://habr.com/ru/post/984909/


All Articles