在PowerShell中控制函数返回的类型 [英] Controlling the type returned by a Function in PowerShell

查看:169
本文介绍了在PowerShell中控制函数返回的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在尝试使用WPF表单为搜索应用程序创建GUI。我的表单有一个TextBox和ComboBox供输入,每次更改事件触发时,其内容都将用作过滤器。 $ var_SearchRegion 是我的组合框, $ var_SearchFor 是我的文本框,和 $ var_DGDisplay 是返回数据的DataGrid。

So, I'm trying to create a GUI for a search application using a WPF form. My form has a TextBox and ComboBox for input, and the contents are applied as a filter every time the change events fire. $var_SearchRegion is my ComboBox, $var_SearchFor is my TextBox, and $var_DGDisplay is my DataGrid for the return data.

为了设置过滤器,我创建了一个基本函数。我知道有比 If Then ElseIf树更干净的方法来执行此操作,但这很快并且可以正常工作。该函数如下所示:

In order to set the filter, I have created a basic function. I know there are cleaner ways to do this than an If Then ElseIf tree, but this was quick and it works. The function looks like this:

Function GetFilteredItems
{
    $RSelect = $var_SearchRegion.SelectedValue.Content
    $PF = $var_SearchFor.Text
    $RF = If ($RSelect -eq 'All Regions') {''} Else {$RSelect}
    If ($PF -eq '' -and $RF -eq '')
    {
        $DPST
    }
    ElseIf ($PF -eq '')
    {
        $DPST | ? {$_.Region -eq $RF}
    }
    ElseIf ($RF -eq '')
    {
        $DPST | ? {$_.FilePath -like "*$PF*"}
    }
    Else
    {
        $DPST | ? {$_.Region -eq $RF -and $_.FilePath -like "*$PF*"}
    }
}

当过滤器将数据集精简为一个条目并将其返回时,就会发生此问题。在使用.NET方法使用PowerShell之前,我曾遇到过这个问题,并且我假设类型从[something]的[Array]更改为仅 something,这会导致WPF对象出现问题。

The issue happens when the filter reduces the dataset to exactly one entry and returns it. I have had this problem before with PowerShell using .NET methods, and I am assuming the type changes from [Array] of "something" to just "something", and that is causing issues with the WPF objects.

这是事件处理程序代码的示例,当过滤器将我的返回值设置为1项时,会引起问题:

Here is an example of the event handler code which is causing problems when the filter gets my return set down to 1 item:

$var_SearchFor.Add_TextChanged({
    $var_DGDisplay.ItemsSource = GetFilteredItems
    $var_DGDisplay.Refresh
})

GetFilteredItems 返回1个项目时,出现此错误:

When GetFilteredItems returns 1 item, I get this error:

Exception setting "ItemsSource": "Cannot convert the "@{Region=SW; 
FilePath=\\server\share\folder\file.ext}" value of type 
"Deserialized.System.Management.Automation.PSCustomObject" to type "System.Collections.IEnumerable"."
At C:\Users\Matthew\GUITest.ps1:90 char:5
+     $var_DGDisplay.ItemsSource = GetFilteredItems
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

我可以通过包装函数调用轻松地解决此问题并显式转换为[array]类型,例如:

I can easily "fix" this problem by wrapping the function call and explicitly converting to an [array] type, like this:

$var_SearchFor.Add_TextChanged({
    $var_DGDisplay.ItemsSource = [array](GetFilteredItems)
    $var_DGDisplay.Refresh
})

但是必须这样做。我应该能够以某种方式在函数中修复此问题。但是,用相同的 [array]()来包装函数的输出行(在4个地方)并不能解决问题。我在PowerShell高级功能中找到了一些信息,在这里我可以使用语法 [OutputType([Array])] 来指定输出类型,但是即使我验证了 System.Array 作为我的输出类型,使用(Get-Command GetFilteredItems).OutputType ,它仍然会失败错误。

But it feels backwards to have to do this. I should be able to fix this inside the function somehow. However, wrapping the output lines of the function (in 4 places) with the same [array]() did not do the trick. I found some information on PowerShell Advanced Functions, where I could use the syntax [OutputType([Array])] to designate the output type, but even though I verified I was getting System.Array as my output type using (Get-Command GetFilteredItems).OutputType, it would still fail with the same error.

TL; DR-有没有一种方法可以避免必须用 [array]()并仍使其与WPF DataGrid控件的ItemSource属性一起使用?

TL;DR - Is there a way to avoid having to wrap my function call with [array]() and still make it work with my WPF DataGrid control's ItemSource Property?

推荐答案


  • 默认情况下,PowerShell 枚举从函数输出的集合(无论是隐式输出还是通过 return 语句输出)

    • PowerShell by default enumerates collections that you output from a function (whether you output them implicitly or via a return statement)


      • 为防止这种情况,请使用 Write-Output -NoEnumerate ,或者更简单有效地(但更加晦涩),将输出集合包装在单元素辅助中。数组(,$ collection )-有关更多信息,请参见此答案

      • To prevent that, use Write-Output -NoEnumerate or, more simply and efficiently (but more obscurely), wrap the output collection in a single-element aux. array (, $collection) - see this answer for more information.

      在您的情况下,您还需要确保要包装的内容是本身始终是一个集合,您可以使用 @()或将其强制转换为 [array]

      In your case, you additionally need to make sure that what you're wrapping is itself always a collection, for which you can use @() or cast to [array].

      Function GetFilteredItems
      {
          $RSelect = $var_SearchRegion.SelectedValue.Content
          $PF = $var_SearchFor.Text
          $RF = If ($RSelect -eq 'All Regions') {''} Else {$RSelect}
      
          # Collect your command's output in an array-typed variable ([object[]])
          [array] $result = 
            If ($PF -eq '' -and $RF -eq '')
            {
              $DPST
            }
            ElseIf ($PF -eq '')
            {
              $DPST | ? {$_.Region -eq $RF}
            }
            ElseIf ($RF -eq '')
            {
              $DPST | ? {$_.FilePath -like "*$PF*"}
            }
            Else
            {
              $DPST | ? {$_.Region -eq $RF -and $_.FilePath -like "*$PF*"}
            }
      
          # Output the array $result as-is, via an aux. wrapper array.
          , $result
      
      }
      

      注意:您不t严格需要直接的 $ result 变量;您可以直接使用,@(if ...)

      Note: You don't strictly need the immediate $result variable; you could use , @(if ...) directly.

      但是,请注意,在两种情况下,命令的输出 stream (在创建对象时发出对象),因为必须在aux之前先收集整个输出。数组可以围绕它构造。

      However, note that in neither case will the command's output stream (emit objects as they're being created), because the entire output must be collected first, before the aux. array can be constructed around it.

      这篇关于在PowerShell中控制函数返回的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆