简体   繁体   English

在PowerShell中将WPF XAML链接到DataGrid

[英]Link WPF XAML to DataGrid in PowerShell

I was following along with the guide located here trying to make a GUI with PowerShell, and it all goes well except I have a DataGrid that needs to be populated in my GUI. 我遵循了此处的指南尝试使用PowerShell制作GUI,并且一切正常,除了需要在GUI中填充DataGrid之外。

In my XML grid I have: 在我的XML网格中,我有:

[xml]$form=@"
<Window
    [...]
    <Grid>
        [...]
        <DataGrid Name="CSVGrid" HorizontalAlignment="Left" Height="340" Margin="10,60,0,0" VerticalAlignment="Top" Width="765"/>
        [...]
    </Grid>
</Window>
"@

Now in the tutorial to create the form it uses the following: 现在,在教程中使用以下内容来创建表单:

$XMLReader = (New-Object System.Xml.XmlNodeReader $Form)
$XMLForm = [Windows.Markup.XamlReader]::Load($XMLReader)

But to get my DataGrid to work, I believe I need to define my "CSVGrid" DataGrid as " system.Windows.Forms.DataGridView " somewhere, but I'm not sure how to tie that together. 但是,让我的DataGrid的工作,我相信我需要定义我的“CSVGrid” DataGrid中为“system.Windows.Forms.DataGridView”的地方,但我不知道如何配合一起。 Running it without defining this will spit out errors if I try to invoke any DataGrid properties, like setting column amounts or column names. 如果我尝试调用任何DataGrid属性(例如设置列数量或列名称),而没有定义此参数而运行它,则会吐出错误。

Any ideas? 有任何想法吗?

The way POSHGUI implements their forms actually works perfectly for my purpose, but I prefer editing the WPF forms in Visual Studio. POSHGUI实现其表单的方式实际上可以很好地达到我的目的,但是我更喜欢在Visual Studio中编辑WPF表单。 If need be, I can rebuild the form in POSHGUI but hopefully there's a way to tie this together here so I can continue to use the VS GUI for editing the form's GUI. 如果需要,我可以在POSHGUI中重建表单,但希望这里有一种方法可以将其捆绑在一起,以便我可以继续使用VS GUI来编辑表单的GUI。

Edit: It should be noted there's not just the data grid on the form, in case that wasn't clear. 编辑:应该注意的是,如果不清楚,在表单上不仅有数据网格。

Edit 2: As an extra bit of info, the way POSHGUI formats the controls is like so: 编辑2:作为额外的信息,POSHGUI格式化控件的方式如下:

#the form itself
$Form                            = New-Object system.Windows.Forms.Form
$Form.ClientSize                 = '400,400'
$Form.text                       = "Form"
$Form.TopMost                    = $false
#a datagrid
$DataGridView1                   = New-Object system.Windows.Forms.DataGridView
$DataGridView1.width             = 382
$DataGridView1.height            = 335
$DataGridView1.location          = New-Object System.Drawing.Point(8,55)
#a button
$Button1                         = New-Object system.Windows.Forms.Button
$Button1.text                    = "My button"
$Button1.width                   = 126
$Button1.height                  = 30
$Button1.location                = New-Object System.Drawing.Point(156,13)
$Button1.Font                    = 'Microsoft Sans Serif,10'

It then ties them together with: 然后将它们与以下内容联系在一起:

$Form.controls.AddRange(@($DataGridView1,$Button1))

So that happily defines the DataGrid variable as a "system.Windows.Forms.DataGridView", &c, whereas the method of putting the entire XML into a $variable and passing that into a "System.Xml.XmlNodeReader" doesn't make the distinction I don't believe, which is why I'm unable to call any DataGrid properties. 因此,很高兴将DataGrid变量定义为“ system.Windows.Forms.DataGridView”,&c,而将整个XML放入$ variable并将其传递到“ System.Xml.XmlNodeReader”的方法并没有使我不相信这种区别,这就是为什么我无法调用任何DataGrid属性的原因。

But again, I'd rather create the GUI in Visual Studio if I can... 但是,如果可以的话,我宁愿在Visual Studio中创建GUI。

Edit 3: If it helps at all, checking the intellisense dropdown, various DataGrid properties are there, but not ColumnCount for example: 编辑3:如果有帮助,请检查intellisense下拉列表,那里有各种DataGrid属性,但没有ColumnCount例如:

在此处输入图片说明

So maybe it's working as intended? 所以也许它按预期工作了? But at the same time, if my DataGrid variable is defined explicitly as a system.Windows.Forms.DataGridView, like in the POSHGUI example, then setting ColumnCount works flawlessly... 但是同时,如果像在POSHGUI示例中一样,将我的DataGrid变量显式定义为system.Windows.Forms.DataGridView,则设置ColumnCount会很顺利。

Before we get too far into it, you can't use a DataGridView in WPF (which is what I'll be showing you here). 在深入探讨之前,您不能在WPF中使用DataGridView (这就是我将在此处显示的内容)。 You can , however, use a DataGrid instead which is pretty much the same thing (and wayyyy shorter and easier in PowerShell than Windows Forms, which is what POSHGUI uses (awesome tool though it is). 但是,您可以改为使用DataGrid ,它几乎是同一件事(在PowerShell中,比Windows Forms更短,更容易,这就是POSHGUI所使用的(虽然它是很棒的工具)。

If you're still interested though, here's a super basic walkthrough of how you could do this. 如果您仍然感兴趣,这里是如何完成此操作的超级基本演练。 First, to define the XAML 首先,定义XAML

$inputXML = @"
<Window x:Class="WpfApp2.MainWindow"
    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:WpfApp2"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <DataGrid Name="Datagrid" AutoGenerateColumns="True" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="180" />
            <DataGridTextColumn Header="Type" Binding="{Binding Type}" Width="233"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
</Window>
"@ 

Note that we are defining which columns from our input object we wanna display. 请注意,我们正在定义要显示的输入对象中的哪些列。 Haven't found a great way to automatically create them yet. 尚未找到一种自动创建它们的好方法。

Next, load the form (using the method from my walkthrough on the topic here ) 接下来,加载表单(使用我在本主题中的演练中的方法

$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML

    $reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch [System.Management.Automation.MethodInvocationException] {
    Write-Warning "We ran into a problem with the XAML code.  Check the syntax for this control..."
    write-host $error[0].Exception.Message -ForegroundColor Red
    if ($error[0].Exception.Message -like "*button*"){
        write-warning "Ensure your &lt;button in the `$inputXML does NOT have a Click=ButtonClick property.  PS can't handle this`n`n`n`n"}
}
catch{#if it broke some other way <span class="wp-smiley wp-emoji wp-emoji-bigsmile" title=":D">:D</span>
    Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."
        }

#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================

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

Now, to add some items to this DataGridView. 现在,向此DataGridView添加一些项目。 The above code also gives us a variable titled $WPFGridView in our session. 上面的代码在我们的会话中还为我们提供了一个名为$WPFGridView的变量。 We can add child items to our DataGridView by calling the .AddChild() method of that variable and feeding it items that have at least the same properties as we defined in our DataGrid earlier. 我们可以通过调用该变量的.AddChild()方法并向其提供至少具有与我们先前在DataGrid定义的属性相同的属性的项,来将子项添加到DataGrid

$WPFDatagrid.AddChild([pscustomobject]@{Name='Stephen';Type=123})
$WPFDatagrid.AddChild([pscustomobject]@{Name='Geralt';Type=234})

Then, to display our GUI, we call the $Form 's ShowDialog() method like so, and then the bottom should greet us. 然后,为了显示我们的GUI,我们像这样调用$FormShowDialog()方法,然后底部应该向我们打招呼。

$Form.ShowDialog()

该图像描绘了一个Windows 10操作系统,其中显示了Windows Presentation Foundation用户界面,该界面包含一个数据网格,该网格具有两列,其中包含上述代码片段中添加的项目

Full code sample is available here . 完整的代码示例可在此处获得 If you want to learn more about using WPF GUI elements like this, I have a full walkthrough available here . 如果您想了解有关使用WPF GUI元素的更多信息, 请点击此处获得完整的演练

I modified it a bit: 我修改了一下:

  • is a function (allows for multiple windows) 是一个函数(允许多个窗口)
  • returns an array of the elements 返回元素的数组
  • loads the presentation framework (supports x:Bind as Binding) 加载演示文稿框架(支持x:Bind作为绑定)
  • you can create any WPF form with visual studio and load it (mostly, do not forget any extra classes used to be defined within the XAML and maybe load its type in posh) 您可以使用Visual Studio创建任何WPF表单并将其加载(大多数情况下,请不要忘记XAML中曾经定义的任何其他类,也可以将其类型加载到posh中)

A more advanced version: supporting click handler 更高版本: 支持点击处理程序

function LoadXamlForm
{

    Param
    (
        [Parameter(Mandatory=$true)] $xamlFile
    )

    Add-Type -AssemblyName PresentationFramework

    $inputXML = Get-Content -Path $xamlFile


    # https://stackoverflow.com/a/52416973/1644202

    $inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window' -replace "x:Bind", "Binding"
    [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
    [xml]$XAML = $inputXML
    #Read XAML

        $reader=(New-Object System.Xml.XmlNodeReader $XAML) 
    try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
    catch [System.Management.Automation.MethodInvocationException] {
        Write-Warning "We ran into a problem with the XAML code.  Check the syntax for this control..."
        write-host $error[0].Exception.Message -ForegroundColor Red
        if ($error[0].Exception.Message -like "*button*"){
            write-warning "Ensure your &lt;button in the `$inputXML does NOT have a Click=ButtonClick property.  PS can't handle this`n`n`n`n"}
    }
    catch{#if it broke some other way <span class="wp-smiley wp-emoji wp-emoji-bigsmile" title=":D">:D</span>
        Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."
            }

    #===========================================================================
    # Store Form Objects In PowerShell
    #===========================================================================
    $Elements = @{}
    $xaml.SelectNodes("//*[@Name]") | %{ $Elements[$_.Name] = $Form.FindName($_.Name) }

    return $Form, $Elements
}


$Form,$Elements = LoadXamlForm .\gui.xaml

$Elements.lvApps.AddChild([pscustomobject]@{Name='Ben';Description="sdsd 343"})

$Form.ShowDialog() | out-null

just any xaml - i know this is no datagrid - but gives you a use case nonetheless 只是任何xaml-我知道这不是datagrid-但仍然为您提供了一个用例

<Window x:Class="WpfApp.MainWindow"
    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:WpfApp2"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ListView SelectionMode="Multiple" x:Name="lvApps" Height="371" VerticalAlignment="Top">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Height="64" AutomationProperties.Name="{Binding Name}">
                        <Ellipse Height="48" Width="48" VerticalAlignment="Center">
                            <Ellipse.Fill>
                                <ImageBrush ImageSource="{Binding ButtonImage}"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <StackPanel Orientation="Vertical" VerticalAlignment="Center" Margin="12,0,0,0">
                            <TextBlock Text="{Binding Name}" />
                            <TextBlock Text="{Binding Description}" />
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Window>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM