将Click事件添加到PowerShell中的WPF DataGrid Button列

时间:2017-02-17 03:41:59

标签: wpf powershell datagrid

通常我用于带按钮的数据网格列的XAML是这样的:

<DataGridTemplateColumn Header="ButtonColumn">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Click="Click_Handler">Do Something</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

在Powershell中使用XAML但是据我所知,Click =无法使用,因为它会抛出错误:

 "Failed to create a 'Click' from the text 'ClickEvent'.

如何在运行时获取对按钮对象的引用,以添加click事件处理程序?或者有没有办法在Powershell中创建一个可以由XAML事件处理程序中指定的名称触发的函数。

为对象命名并使用

$window.FindName("<button name>")

不能工作

正在构建的GUI的简化示例:

 [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="Demo" WindowStartupLocation = "CenterScreen" 
        SizeToContent="WidthAndHeight"
        ShowInTaskbar = "True">

    <StackPanel Orientation="Vertical" Name="msiStackPanel">
        <TextBlock Margin="20,20,20,20" HorizontalAlignment="Center" FontSize="14" FontWeight="Bold">List of Stuff</TextBlock>
        <DataGrid Name="myGrid" ItemsSource="{Binding}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
                <DataGridTemplateColumn Header="Launch">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Name="x:launchButton">Launch</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Button Margin="20,20,20,20">Completed All Tests</Button>
    </StackPanel>
</Window>
'@

# Set PowerShell variable for each named object in GUI
Function Set-WpfVariables
{
  param($children)
    ForEach ($child in $children.Children)
    {
        Set-WpfVariables -Children $child
        if (![String]::IsNullOrEmpty($child.Name))
        {
            Write-Host "Set variable $($child.Name)"
            Set-Variable -Name $child.Name -Value $child -Scope global
        }    
    }
}

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

$controls = [System.Windows.LogicalTreeHelper]::GetChildren($window)
Set-WpfVariables -Children $controls

$table = New-Object System.Data.DataTable
$table.Columns.Add("Name")
$table.Rows.Add("Row 1")
$table.Rows.Add("Row 2")

$myGrid.DataContext = $table.DefaultView

$window.ShowDialog()

4 个答案:

答案 0 :(得分:1)

在PowerShell中,绑定事件的最简单方法是在解析XAML之后。

这个例子来自this site,给出了一个非常基本但完整的例子:

[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="Blend and PowerShell" 
Width="640" Height="480" AllowsTransparency="False"> 
<Grid x:Name="LayoutRoot"> 
  <Rectangle Margin="22,8,22,0" VerticalAlignment="Top" Height="178" Stroke="#FF000000"> 
   <Rectangle.Fill> 
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
     <GradientStop Color="#FF000000" Offset="0"/> 
     <GradientStop Color="#FF861A1A" Offset="1"/> 
    </LinearGradientBrush> 
   </Rectangle.Fill> 
  </Rectangle> 
  <Button Margin="121,0,129,96" VerticalAlignment="Bottom" Height="100" Content="Button" 
    x:Name="Close"/> 
</Grid> 
</Window> 
"@

# create an xml reader, then load the xaml
$reader = New-Object System.Xml.XmlNodeReader $xaml 
$d = [Windows.Markup.XamlReader]::Load($reader)

# find the button by name, then add a click event to it (which closes the window).
$d.FindName("Close").add_click({ 
    $d.Close() 
})

# show the wpf window
$d.ShowDialog() | out-null

答案 1 :(得分:1)

这是任何感兴趣的人的工作脚本:

[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="Demo" WindowStartupLocation = "CenterScreen" 
        SizeToContent="WidthAndHeight"
        ShowInTaskbar = "True">

    <StackPanel Orientation="Vertical" Name="msiStackPanel">
        <TextBlock Margin="20,20,20,20" HorizontalAlignment="Center" FontSize="14" FontWeight="Bold">List of Stuff</TextBlock>
        <DataGrid Name="myGrid" ItemsSource="{Binding}">
            <DataGrid.Columns>
            </DataGrid.Columns>
        </DataGrid>
        <Button Margin="20,20,20,20">Completed All Tests</Button>
    </StackPanel>
</Window>
'@

# Set PowerShell variable for each named object in GUI
Function Set-WpfVariables
{
  param($children)
    ForEach ($child in $children.Children)
    {
        Set-WpfVariables -Children $child
        if (![String]::IsNullOrEmpty($child.Name))
        {
            Write-Host "Set variable $($child.Name)"
            Set-Variable -Name $child.Name -Value $child -Scope global
        }    
    }
}

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

$controls = [System.Windows.LogicalTreeHelper]::GetChildren($window)
Set-WpfVariables -Children $controls

$table = New-Object System.Data.DataTable
$table.Columns.Add("Name")
$table.Rows.Add("Row 1")
$table.Rows.Add("Row 2")
$table.Rows.Add("Row 3")


#$myGrid.DataContext = $table.DefaultView #This did not work for me. so...
$myGrid = $window.FindName("myGrid")
$myGrid.ItemsSource = $table.DefaultView


[System.Windows.RoutedEventHandler]$clickEvent = {
param ($sender,$e)
    Write-Host "Clicked row $($myGrid.SelectedItem.Row.Name)"
}

$buttonColumn = New-Object System.Windows.Controls.DataGridTemplateColumn
$buttonFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Button])
$buttonFactory.SetValue([System.Windows.Controls.Button]::ContentProperty, "Launch")
$buttonFactory.AddHandler([System.Windows.Controls.Button]::ClickEvent,$clickEvent)
$dataTemplate = New-Object System.Windows.DataTemplate
$dataTemplate.VisualTree = $buttonFactory
$buttonColumn.CellTemplate = $dataTemplate
$myGrid.Columns.Add($buttonColumn)

$myGrid.DataContext = $table.DefaultView

$window.ShowDialog()

答案 2 :(得分:0)

如果您想获得对该按钮的引用,请设置名称:

<Button x:name="button" Click="Click_Handler">Do Something</Button>

然后在您的代码中,您可以使用“按钮”。

button.Click += Click_Handler

我发现您的错误很奇怪,您发布的简短示例会导致错误吗?你可以在你创建Click_Handler的地方发布代码吗?

答案 3 :(得分:0)

以编程方式创建按钮列,允许您设置事件处理程序:

[System.Windows.RoutedEventHandler]$clickEvent = {
param ($sender,$e)

    Write-Host "Clicked row $($myGrid.SelectedItem.Row.Name)"
}

$buttonColumn = New-Object System.Windows.Controls.DataGridTemplateColumn
$buttonFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Button])
$buttonFactory.SetValue([System.Windows.Controls.Button]::ContentProperty, "Launch")
$buttonFactory.AddHandler([System.Windows.Controls.Button]::ClickEvent,$clickEvent)
$dataTemplate = New-Object System.Windows.DataTemplate
$dataTemplate.VisualTree = $buttonFactory
$buttonColumn.CellTemplate = $dataTemplate
$myGrid.Columns.Add($buttonColumn)

$myGrid.DataContext = $table.DefaultView

$window.ShowDialog()

对于已存在的列:

$buttonFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Button])
$buttonFactory.SetValue([System.Windows.Controls.Button]::ContentProperty, "Launch")
$buttonFactory.AddHandler([System.Windows.Controls.Button]::ClickEvent,$clickEvent)
$dataTemplate = New-Object System.Windows.DataTemplate
$dataTemplate.VisualTree = $buttonFactory
$myGrid.Columns[1].CellTemplate = $dataTemplate