Проблема со стилями триггеров / данных в WPF-скрипте powershell - PullRequest
0 голосов
/ 10 января 2020

У меня есть скрипт powershell, который отображается в виде формы WPF, чтобы позволить пользователям управлять принтерами и т. Д. c (map / unmap / set default), все на нем работает нормально, но у меня есть проблема с попыткой скрыть принтер (из работы, где понятные списки ненавидят, когда к ним привязан только 1 элемент)

Поэтому, если у пользователя есть 1 подключенный принтер, я также добавляю в принтер «Отправить в OneNote 16» объект, который привязан к представлению списка, но во избежание путаницы я бы идеально хотел скрыть этот принтер из списка.

Раздел кода XAML

<ListBox x:Name="MyListbox" HorizontalContentAlignment="Stretch">
      <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="ListBoxItem.Visibility" Value="Visible"/>
          <Style.Triggers>
            <DataTrigger Binding="{Binding Path=Name}" Value="Send to OneNote 16">
              <Setter Property="ListBoxItem.Visibility" Value="Collapsed"/>
            </DataTrigger>
          </Style.Triggers>
        </Style>
      </ListBox.ItemContainerStyle>
      <ListBox.ItemTemplate>
        <DataTemplate>
          <Border CornerRadius="6" BorderBrush="LightGray" Background="White" BorderThickness="1" Padding="8">
              <StackPanel>
                <DockPanel>
                  <TextBlock Text="Name: " FontWeight="Bold" Foreground="LimeGreen" />
                  <TextBlock>
                      <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
                  </TextBlock>
                </DockPanel>
                <DockPanel>
                  <TextBlock Text="Server: " />
                  <TextBlock Foreground="Black">
                      <TextBlock Text="$($PrintServerName)" />
                  </TextBlock>
                  <TextBlock Text=" | Job Count: " />
                  <TextBlock Foreground="Black">
                      <TextBlock Text="{Binding Path=JobCount}" />
                  </TextBlock>
                </DockPanel>
              </StackPanel>
            </Border>
          </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

Бит Powershell, который заполняет объект, связанный с MyListBox

    function Get-MappedPrinterInfo {

  BEGIN { 

    # Setup variables, and get mapped printer information from registry
    [object]$Printers = Get-ChildItem Registry::\HKEY_CURRENT_USER\Printers\Connections
    [object]$Output = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
  }

  PROCESS {

    foreach ($Printer in $Printers) {

      # Extract printer name
      [string]$PrinterName = $Printer.Name

      # Correct Case
      $PrinterName = $PrinterName.ToLower()

      # Cleanup data
      $PrinterName = $PrinterName.replace("printerserver.mynetwork.local", "")
      $PrinterName = $PrinterName.replace("printerserver", "")
      $PrinterName = $PrinterName.replace("hkey_current_user\printers\connections\", "")
      $PrinterName = $PrinterName.replace(",", "")

      # Get additional data on printer from its print server
      $Output += Get-Printer -ComputerName $PrintServerName | Where-Object Shared -eq $true | Where-Object Name -eq $PrinterName
    }

    # Check object length, and pad out if required.
    if ($Output.Count -eq 1) {
      $Output += Get-Printer | Where-Object Name -eq "Send to OneNote 16"
    }
  }

  END {

    # Return data
    return $Output
  }
}

# Populate my mapped printer list.
$MyListbox.ItemsSource = Get-MappedPrinterInfo

Раздел стилей все работает, но обработчик данных никогда не запускается, если я устанавливаю свойство Setter (4-я строка в разделе XAML), тогда я могу скрыть / показать все элементы, но в идеале я хочу чтобы можно было прятаться по имени.

Заранее спасибо.

1 Ответ

2 голосов
/ 10 января 2020

Нет необходимости в вашем обходном решении «добавить-дополнительный-элемент-затем-скрыть-это»:

* * * * * * * * * Проблема, связанная с root, заключается в том, что вывод коллекции из функции PowerShell приводит к ее перечисление по умолчанию, которое в случае коллекции single-item означает, что этот элемент сам выводится, а не массив элементов ( [object[]], так как PowerShell неявно собирает несколько выходных данных из команды, когда вы присваиваете значение l).

@(), оператор подвыражения массива , существует именно для обратитесь к этому сценарию:

Вы заключаете его в команду, вывод которой вы всегда хотите рассматривать как массив, даже если команда выводит единственный объект:

# Populate my mapped printer list.
# @(...) ensures that the function output is an array.
$MyListbox.ItemsSource = @(Get-MappedPrinterInfo)

Обратите внимание, что эту проблему можно решить из внутри вашей функции - обернув вашу выходную коллекцию в aux. массив из одного элемента, так что исходная коллекция принимается вызывающей стороной - но обычно лучше не писать такие функции, так как они будут демонстрировать нестандартное поведение при использовании в конвейере, где другие команды ожидают поэлементно ввод, а не целые коллекции.

Если вы все же хотите это сделать (что хорошо для частных, специальных функций):

...
END {
    # Return data wrapped in a single-item aux. array to ensure 
    # that the $Output collection is returned as a whole.
    return , $Output
}

Несколько сторон в отношении вашего кода:

[object]$Printers = ...

Приведение [object] бессмысленно в PowerShell, и приведение обычно не работает так же, как в C# Например,

Независимо от того, какой тип у RHS, становится эффективным типом $Printers.

Если вы используете тип Speci c для ограничения LHS, однако преобразование в этот тип выполняется при каждом назначении значения этой переменной.


$Output += ...

+= тихо преобразует $Output в (новый экземпляр) массив ([object[]]) независимо от исходного типа, который не является вашим намерением и также неэффективен.

Вам нужно вызвать метод .Add() для экземпляра коллекции, изначально сохраненного в $Output.

...