I am limiting drag and drop actions to a WPF listbox control in Powershell to only allow text files to be dropped. I would like to use the System.Windows.DragDropEffects property to prevent the drop action on the DragEnter event as it also changes the mouse cursor providing user feedback for the denied drop action. I can still limit the action taken on the dropped file by validating the file extension on the Drop event. But I would prefer to prevent the drop action all together for smoother user interaction.
In debugging I've verified that the DragDropEffect property is being set correctly, however the event handler does not seem to reflect the change. I believe it might be a limitation trying to use the DragEventArgs Class to monitor the event through the Powershell pipeline.
Code for the WPF listbox DragEnter event is below. I noticed that the object passed in the $_ pipeline is of the System.Windows.DragEventArgs class.
$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'
}
}
}
})
Setting DragDropEffect property using WinForms listbox works as expected. The mouse changes and the drop event is prevented. However here, the object passed in the $_ pipeline is of the 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()
Full test code below for 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()
Any thoughts or suggestions is appreciated!!