将WPF XAML链接到PowerShell中的DataGrid

时间:2018-09-19 12:26:49

标签: wpf powershell datagrid

我一直遵循here中的指南,尝试使用PowerShell制作GUI,并且一切顺利,除了我的GUI中需要填充一个DataGrid。

在我的XML网格中,我有:

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

现在在本教程中,它使用以下内容来创建表单:

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

但是要使我的DataGrid正常工作,我相信我需要在某个地方将“ CSVGrid” DataGrid定义为“ system.Windows.Forms.DataGridView ”,但是我不确定如何绑定在一起。如果我尝试调用任何DataGrid属性(如设置列数量或列名称),则在不定义此内容的情况下运行它会吐出错误。

有什么想法吗?

POSHGUI实现其表单的方式实际上可以很好地达到我的目的,但是我更喜欢在Visual Studio中编辑WPF表单。如果需要,我可以在POSHGUI中重建表单,但希望这里有一种方法可以将其捆绑在一起,以便我可以继续使用VS GUI来编辑表单的GUI。

编辑:应该注意的是,如果不清楚,表单上不仅有数据网格。

编辑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'

然后将它们与以下内容联系在一起:

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

因此,很高兴将DataGrid变量定义为“ system.Windows.Forms.DataGridView”,&c,而将整个XML放入$ variable并将其传递到“ System.Xml.XmlNodeReader”的方法没有实现”不能做出我不相信的区别,这就是为什么我无法调用任何DataGrid属性的原因。

但是,如果可以的话,我宁愿在Visual Studio中创建GUI。

编辑3:如果完全有帮助,请检查intellisense下拉列表,可以找到各种DataGrid属性,例如,没有ColumnCount:

enter image description here

所以它可能按预期工作了?但是同时,如果像在POSHGUI示例中一样,将我的DataGrid变量显式定义为system.Windows.Forms.DataGridView,则设置ColumnCount会完美无瑕...

2 个答案:

答案 0 :(得分:3)

在深入探讨之前,您不能在WPF中使用 DataGridView (这就是我将在此处显示的内容)。但是,您可以 使用 DataGrid ,它几乎是同一件事(并且在PowerShell中比Windows Forms更短,更容易,这是POSHGUI所使用的(很棒的工具)。

但是,如果您仍然感兴趣,这里是如何完成此操作的超级基本演练。首先,定义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>
"@ 

请注意,我们正在定义要显示的输入对象中的哪些列。尚未找到一种自动创建它们的好方法。

接下来,加载表单(使用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)}

现在,向此DataGridView添加一些项目。上面的代码还为我们在会话中提供了名为$WPFGridView的变量。我们可以通过调用该变量的.AddChild()方法并将其提供的属性至少与我们先前在DataGrid中定义的属性相同的项添加到DataGridView中。

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

然后,要显示我们的GUI,我们像这样调用$Form的{​​{1}}方法,然后底部应该向我们打招呼。

ShowDialog()

The image depicts a Windows 10 operating system displaying a Windows Presentation Foundation User Interface which contains a datagrid with two columns that contain the items added in the code snippet above

完整代码示例为available here。如果您想了解更多有关使用WPF GUI元素的信息,请参阅full walkthrough available here

答案 1 :(得分:1)

我做了一些修改:

  • 是一个功能(允许多个窗口)
  • 返回元素数组
  • 加载演示文稿框架(支持x:Bind作为绑定)
  • 您可以使用Visual Studio创建任何WPF表单并加载它(通常,不要忘记XAML中曾经定义的任何其他类,甚至可以将其类型加载到posh中)

更高级的版本: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

只是任何一个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>