Powershell CollectionViews

1.1k views Asked by At

I am trying to do grouped items in a WPF ComboBox using XAML, and I found this that talks about using a list to drive the grouping. But the example Code Behind is of course not Powershell, and I am having a heck of a time groking how to build the list. Can someone point me at a good resource on CollectionViews in Powershell? I have zero experience in C/C++/C#, though I hope Powershell ends up being a gateway drug. ;) BTW, I did find this, that talks about doing the collection view in XAML, but the content of my collectionView is going to be dynamic, so I have to build it in code.

BTW, the ultimate goal is a combo box that looks like this...

Sets
   Arch
   MEP
   Viz

Packages
   RVT_2015
   RVT_2016
   MAX_2016

... where the actual sets and packages are dynamically pulled from some user customized XML, and the user can pick one set, or one package. Trying to do two lists and enforce one choice with a UX that isn't frustrating has been, less than effective. So I thought a single grouped combo box would address the problem nicely.

EDIT: Woot to progress!

$locations = @('Amsterdam', 'Berlin', 'London')
$sets = @('Arch', 'MEP', 'Viz')
$packages = @('RVT_2015', 'RVT_2016', 'MAX_2016')

[xml]$xaml = @"
<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen" ResizeMode="NoResize"
    Width = "300" Height = "200" ShowInTaskbar = "True" Background = "lightgray"> 
    <StackPanel>
        <Label  Content="Define your job:" VerticalAlignment="Center" HorizontalAlignment="Left"  />
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0" Grid.Column="0" Content="Location" VerticalAlignment="Center" HorizontalAlignment="Left"  />
            <ComboBox Name="Location" Width="200"  
                Grid.Row="0" Grid.Column="1"
                VerticalAlignment="Center" HorizontalAlignment="Right"
                VerticalContentAlignment="Center"  
                Margin="0,0,0,0">             
            </ComboBox>

            <Label Grid.Row="1" Grid.Column="0" Content="Target" VerticalAlignment="Center" HorizontalAlignment="Left"  />
            <ComboBox Name="Target"  
                Grid.Row="1" Grid.Column="1"
                VerticalAlignment="Center" HorizontalAlignment="Right"
                VerticalContentAlignment="Center" 
                Width="200" Margin="0,0,0,0">
                <ComboBox.GroupStyle>
                    <GroupStyle>
                        <GroupStyle.HeaderTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                        </GroupStyle.HeaderTemplate>
                    </GroupStyle>
                </ComboBox.GroupStyle>
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </Grid>
    </StackPanel>
</Window>
"@

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$window=[Windows.Markup.XamlReader]::Load($reader)

$data = @() 
foreach ($target in $sets) {
    $data += New-Object PSObject -prop @{Name="$target";Category="Sets"}
}
foreach ($target in $packages) {
    $data += New-Object PSObject -prop @{Name="$target";Category="Packages"}
}

$listView = [System.Windows.Data.ListCollectionView]$data
$listView.GroupDescriptions.Add((new-object System.Windows.Data.PropertyGroupDescription "Category"))

$location = $window.findname("Location")
$location.ItemsSource = $locations

$target = $window.findname("Target")
$target.ItemsSource = $listView


$window.ShowDialog() | out-null
1

There are 1 answers

6
Jan Chrbolka On BEST ANSWER

Based on the first example you have linked in your question, here is a simple implementation in PowerShell

Add-Type –assemblyName WindowsBase
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName PresentationFramework

[xml]$xaml = @"
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <ComboBox Name="comboBox" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left"  
        Margin="10,20,0,0">
        <ComboBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ComboBox.GroupStyle>
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>
"@

$reader = (New-Object Xml.XmlNodeReader $xaml) 
$GUIWindow = [Windows.Markup.XamlReader]::Load( $reader ) 

$xaml.SelectNodes("//*[@Name]") | % {Set-Variable -Name ($_.Name) -Value $GUIWindow.FindName($_.Name)}

$data = @() 
$data += New-Object PSObject -prop @{Name="Arch";Category="Sets"}
$data += New-Object PSObject -prop @{Name="MEP";Category="Sets"}
$data += New-Object PSObject -prop @{Name="Viz";Category="Sets"}
$data += New-Object PSObject -prop @{Name="RVT_2015";Category="Packages"}
$data += New-Object PSObject -prop @{Name="RVT_2016";Category="Packages"}
$data += New-Object PSObject -prop @{Name="MAX_2016";Category="Packages"}

$lview = [System.Windows.Data.ListCollectionView]$data
$lview.GroupDescriptions.Add((new-object System.Windows.Data.PropertyGroupDescription "Category"))
$comboBox.ItemsSource = $lview


$GUIWindow.ShowDialog() | out-null

This is very basic, but you can build on that.

EDIT:

Original answer was using the following two lines:

$lview = [System.Windows.Data.ListCollectionView]::new($data)
$lview.GroupDescriptions.Add([System.Windows.Data.PropertyGroupDescription]::new("Category"))

They work in PS5, but will produce an error in all previous version of PowerShell. The workaround is to use Typecasting for ListCollectionView. This works in PS2.

$lview = [System.Windows.Data.ListCollectionView]$data
$lview.GroupDescriptions.Add((new-object System.Windows.Data.PropertyGroupDescription "Category"))

I have edited the code with this workaround.