【问题标题】:Using XAML/WPF in PowerShell, how do I populate a list box?在 PowerShell 中使用 XAML/WPF,如何填充列表框?
【发布时间】:2016-11-09 22:44:40
【问题描述】:

我在这里找到了许多很棒的主题,但似乎无法找到我的答案。我正在使用 Visual Studio 制作一个 GUI,并将 XAML 复制/粘贴到 PowerShell 中。我知道我应该在 c# 中执行此操作,但由于我的知识还不存在,它对我来说是纯 PowerShell。

所以我已经制作了我的 GUI,但我似乎无法填充我的数据字段。做文本框之类的其他事情是可以解决的,但我似乎无法让这个列表视图/数据网格填充值。

此时,与 Azure 的连接已被删除,直到我可以解决将项目添加到列表框中的问题。

XAML 来绘制我的表单

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

将 XAML 加载到内存/创建对象

#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)}

我可能需要帮助的地方

#Try to setup a dummy entry
$vmpicklistView.items.Add( @{'VMName'='1';Status="AccessDenied";'Other'='1'})

#===========================================================================
# Shows the form
#===========================================================================
$Form.ShowDialog() | out-null

正如您从我的屏幕截图中看到的那样,当我向列添加绑定时(我认为这会实例化列并让我为它们插入值……不)当我尝试添加时它们不再更新一个新项目。但是,我没有应用绑定的“其他”列至少显示了一些输入,但它错误地列出了 Collection,就好像它试图显示整个哈希表一样。

那么,我的最后一个问题是,如何将项目添加到列表视图?

【问题讨论】:

    标签: c# wpf xaml powershell


    【解决方案1】:

    好吧,我想出了答案。事实证明,当我使用 .Add 时,我应该指定一个 PowerShell 自定义对象作为我的重载,而不是像以前那样简单的哈希表。当我将代码更改为以下内容时:

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

    然后也修改我的 Add 语句:

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

    我可以像这样填充我的字段

    #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"})}
    }
    

    为什么我必须这样做?

    这是我对为什么需要这样做的解释。 PowerShell 自定义对象提供了一个具有命名值的对象,我可以使用绑定将其提取出来,而哈希表是键/值对的集合,不太适合此目的。

    我希望这个答案可以帮助其他像我一样被难住的人!

    【讨论】:

      【解决方案2】:

      WPF 通常用于绑定到视图模型对象属性,而不是字典或哈希表条目。有一种语法可以绑定到字典条目,这将使 GridViewColumn 绑定看起来像这样:

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

      注意使用方括号表示该值来自索引器。

      至于为什么“Other”列显示为“(Collection)”,我认为默认绑定只是要显示对象,WPF 必须将字典和哈希表呈现为“(Collection)”

      尝试为其他添加类似的绑定:

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

      【讨论】:

      • 这是一个很好的响应,但添加 [] 括号会导致空白列。在此期间,我能够解决我的问题,但我感谢您抽出时间留下如此详细的回复。
      • @FoxDeploy 嗯,我试过了,让列正确显示。但您的解决方案可能比更改各处的所有绑定更简单。
      【解决方案3】:

      有一种更简单的方法。

      假设你有一个类似于上述问题的设置

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

      在 Powershell 中,您会得到来自某个提供者(在本例中为 ConfigurationManager)的对象列表

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

      现在这个开箱即用的属性与我的 DisplayMemberBindings 不一致,所以我们必须创建一个对象集合来这样做

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

      现在(假设加载 XAML 并发现命名元素并将它们放入 powershell 变量的代码已经运行)

      $Collections.ItemsSource = $BindableDCs
      

      完成。

      或者,如果您想使用单层 powershell 方式进行操作

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

      【讨论】: