在 PowerShell 中使用 XAML/WPF,如何填充列表框?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29544866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using XAML/WPF in PowerShell, how do I populate a list box?
提问by FoxDeploy
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.
我在这里找到了许多很棒的主题,但似乎无法找到我的答案。我正在使用 Visual Studio 制作 GUI 并将 XAML 复制/粘贴到 PowerShell 中。我知道我应该用 c# 来做这件事,但由于我的知识还不存在,它对我来说是纯粹的 PowerShell。
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.
所以我已经制作了我的 GUI,但我似乎无法填充我的数据字段。做其他事情,比如文本框是可以解决的,但我似乎无法让这个列表视图/数据网格填充值。


At this moment, the connection to Azure has been removed, until I can resolve this hitch of adding items to my list box.
此时,与 Azure 的连接已被移除,直到我可以解决将项目添加到我的列表框的问题。
XAML to draw my form
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>
'@
Loading the XAML into memory/making objects
将 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)}
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.
正如您从我的屏幕截图中看到的,当我向列添加绑定时(我认为这会实例化列并让我为它们插入值......不)当我尝试添加新项目时它们不再更新. 但是,我没有应用绑定的“其他”列至少显示了 someput,但它错误地列出了 Collection,就好像它试图显示整个哈希表一样。
So, my final question, how do I add items to a listview?
所以,我的最后一个问题是,如何将项目添加到列表视图中?
采纳答案by FoxDeploy
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 时,我应该指定一个 PowerShell 自定义对象作为我的重载,而不是像我之前所做的那样一个简单的哈希表。当我将代码更改为以下内容时:
#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:
然后也修改我的 Add 语句:
$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"})}
}


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.
这是我对为什么需要这样做的解释。PowerShell 自定义对象提供了一个带有命名值的对象,我可以使用绑定来提取它,而哈希表是键/值对的集合,不太适合此目的。
I hope this answer has helped anyone else who got stumped as I did!
我希望这个答案能帮助其他像我一样被难住的人!
回答by Mike Zboray
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:
WPF 通常用于绑定到视图模型对象属性,而不是字典或哈希表条目。有一种绑定到字典条目的语法,这将使 GridViewColumn 绑定看起来像这样:
<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)"
至于为什么“其他”列显示为“(集合)”,我相信默认绑定只会显示对象,而 WPF 必须将字典和哈希表呈现为“(集合)”
Try adding a similar binding for Other:
尝试为其他添加类似的绑定:
<GridViewColumn Header="Other" DisplayMemberBinding ="{Binding [Other]}"/>
回答by TofuBug
There is a much simpler way of doing this.
有一种更简单的方法可以做到这一点。
Say you have a setup similar to the question above
假设您有一个类似于上述问题的设置
<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 are getting say the list of objects from some provider (in this case ConfigurationManager)
在 Powershell 中,您会得到来自某个提供程序的对象列表(在本例中为 ConfigurationManager)
$DCs = Get-CMDeviceCollection | ? { $_.CollectionRules.RuleName -contains "OU Query" }
Now this out of the box has properties that do not align with my DisplayMemberBindings so we have to make a collection of objects that do so
现在,这个开箱即用的属性与我的 DisplayMemberBindings 不对齐,因此我们必须制作一组这样做的对象
$BindableDCs = $DCs | Select-Object -Property @{Name='CollectionName';Expression={$_.Name}}, @{Name='CollectionCount';Expression={$_.MemberCount}}
Now (assuming the code to load the XAML and discover the named elements and put them in powershell variables has been run)
现在(假设加载 XAML 并发现命名元素并将它们放入 powershell 变量的代码已运行)
$Collections.ItemsSource = $BindableDCs
Done.
完毕。
Or if you want to do it the one liner powershell way
或者,如果您想以单衬 powershell 方式进行操作
$Collections.ItemsSource = Get-CMDeviceCollection | ? { $_.CollectionRules.RuleName -contains "OU Query" } | Select-Object -Property @{Name='CollectionName';Expression={$_.Name}}, @{Name='CollectionCount';Expression={$_.MemberCount}}

