我正在将拖放操作限制为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()