Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using XAML/WPF in PowerShell, how do I populate a list box?

I've found a number of great threads here but can't seem to track down my answer. I'm making a GUI using Visual Studio and copy/pasting the XAML into PowerShell. I know I should be doing this in c#, but as my knowledge isn't there yet, it's pure PowerShell for me.

So I've got my GUI made, but I can't seem to populate my data fields. Doing other things like textboxes were solvable, but I can't seem to get this listview / data grid to populate with values.

enter image description here

At this moment, the connection to Azure has been removed, until I can resolve this hitch of adding items to my list box.

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>
'@

Loading the XAML into memory/making 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 screen shot, when I added a binding to the columns (which I thought would instantiate the columns and let me plug in values for them...nope) they no longer update when I try to add a new item. However, the 'Other' column, which I did not apply the binding to, does at least show someput, but it incorrectly lists Collection, as if it is trying to display the whole hashtable.

So, my final question, how do I add items to a listview?

like image 488
FoxDeploy Avatar asked Apr 09 '15 17:04

FoxDeploy


Video Answer


2 Answers

Alright, I figured out the answer. It turns out that when I was using .Add, I should have been specifying a PowerShell custom object as my overload, not a simple hashtable as I was doing 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 modify my Add statement as well:

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

I'm able to populate my fields, like so

#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 as to why this was needed. PowerShell Custom Objects provide an Object with Named values, which I can pluck out using bindings, while a hashtable is a collection of Key/Value pairs, not well suited for this purpose.

I hope this answer has helped anyone else who got stumped as I did!

like image 139
FoxDeploy Avatar answered Sep 18 '22 11:09

FoxDeploy


WPF is generally used to bind to viewmodel object properties not dictionary or hashtable entries. There is a syntax to bind to dictionary entries which would make the GridViewColumn bindings look like this:

<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 an indexer.

As for why the "Other" column appears as "(Collection)", I believe the default binding is just going to display the object and WPF must render dictionaries and hashtables as "(Collection)"

Try adding a similar binding for Other:

<GridViewColumn Header="Other" DisplayMemberBinding ="{Binding [Other]}"/>
like image 25
Mike Zboray Avatar answered Sep 18 '22 11:09

Mike Zboray