PowerShell脚本会发出WPF ListBox的拖放效果



我正在将拖放操作限制为powerShell中的WPF列表框控件,以允许删除文本文件。我想使用system.windows.dragdropeffects属性,以防止Dragenter事件的下降操作,因为它还更改了鼠标光标为拒绝的掉落操作提供用户反馈。我仍然可以通过验证Drop事件的文件扩展名来限制在删除文件上采取的操作。但是我宁愿防止掉落动作一起以使用户交互更顺畅。

在调试时,我已经验证了DragDropeFfect属性的设置正确,但是事件处理程序似乎并没有反映更改。我相信试图使用DrageVentargs类通过PowerShell管道监视事件可能是一个限制。

WPF ListBox Dragenter事件的代码如下。我注意到通过$ _管道中传递的对象是system.windows.drageventargs类。

$listbox.Add_DragEnter({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
    foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
        if(([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
            $_.Effects = [System.Windows.DragDropEffects]::All
            Write-Host 'Dropfile is a .TXT'
        }
        else {
            $_.Effects = [System.Windows.DragDropEffects]::None
            Write-Host 'Dropfile is NOT a .TXT'
        }
    }
}
})

使用Winforms ListBox设置DragDropeFfect属性,按预期工作。鼠标更改并防止下降事件。但是,在这里,在$ _管道中传递的对象是system.windows.forms.drageventargs class。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object Windows.Forms.Form
$listbox = New-Object Windows.Forms.ListBox
$listbox.AllowDrop = $true
$listbox.Add_DragEnter({
$_.Effect = [Windows.Forms.DragDropEffects]::None
})
$form.Controls.Add($listbox)
$form.ShowDialog()

WPF下面的完整测试代码:

[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
[xml]$xaml = @'
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Remote Execution Toolkit" Height="300" Width="300">
<Grid>
    <ListBox x:Name="listBox" AllowDrop="True" Height="250" HorizontalAlignment="Center" Width="250">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}">
                    <TextBlock Text="{Binding}" TextAlignment="Left" Width="Auto" />
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>
</Window>
'@
# Load XAML Reader
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )
# Map XAML Controls
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")  | ForEach {
New-Variable  -Name $_.Name -Value $Window.FindName($_.Name) -Force
}
# Drag Event to validate file extensions for drop effect
$listbox.Add_DragEnter({
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
    foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
        if(([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
            $_.Effects = [System.Windows.DragDropEffects]::All
            Write-Host 'Dropfile is a .TXT'
        }
        else {
            $_.Effects = [System.Windows.DragDropEffects]::None
            Write-Host 'Dropfile is NOT a .TXT'
        }
    }
}
})
$Window.ShowDialog()

任何想法或建议都将受到赞赏!!

在大量的Google-foo之后,运行Snoop WPF来监视事件以及反复试验,我意识到我只是订阅了错误的拖放事件。为了达到连续显示操作不允许光标的结果,您必须使用Dragover事件。

$listbox.Add_DragOver({
    ...
    $_.Effects = [System.Windows.DragDropEffects]::None
    ...
})

显然,当在PowerShell中使用WPF代码时,Dragenter事件只会触发一次,允许光标向后更改,而Dragover事件则在鼠标上不允许在操作的控件上保持不允许光标的显示。

希望这能够将另一个开发人员在路上节省一段时间。

更改$_.Effects后添加$_.Handled = $true

这是从这里获取的:https://stackoverflow.com/a/444321363/8262102

# Drag and drop UI example to a list box.
Add-Type -AssemblyName PresentationFramework, System.Drawing, System.Windows.Forms, WindowsFormsIntegration
[xml]$xaml = @'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test Drop Form" Height="300" Width="500">
<Grid>
<ListBox x:Name="listBox" AllowDrop="True" Height="250" HorizontalAlignment="Center" Width="475">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}">
<TextBlock Text="{Binding}" TextAlignment="Left" Width="Auto" />
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
'@
# Load XAML Reader
$reader = New-Object System.Xml.XmlNodeReader $xaml
$Form   = [Windows.Markup.XamlReader]::Load($reader)
# Map XAML Controls
$formNamedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | Sort
$formNamedNodes | ForEach-Object {
  Set-Variable -Name $_.Name -Value $Form.FindName($_.Name) # Set the variable names to the same as that of the controls.
}
# Drop event to add the files to the list box.
$listbox.Add_Drop({
  if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
    foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
      if (([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
        Write-Host "Dropped file extension: $filename is .TXT"
        $listBox.Items.Add($filename)
      }
      else {
        Write-Host "Dropped file extension: $filename is NOT .TXT"
      }
    }
  }
  })
# The DragOver event is there to handle changing the dropped effects.
$listbox.Add_DragOver({
  if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
    foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
      if (([System.IO.Path]::GetExtension($filename).ToUpper() -eq ".TXT")) {
        $_.Effects = [System.Windows.DragDropEffects]::All
        Write-Host "$filename is a .TXT"
      }
      else {
        $_.Effects = [System.Windows.DragDropEffects]::None
        Write-Host "$filename is NOT a .TXT"
      }
      $_.Handled = $true # This is there to handle the effect. This needs to be below $_.Effect.
    }
  }
  })
$Form.WindowStartupLocation = "CenterScreen"
$Form.ShowDialog()

最新更新