Powershell脚本问题处理WPF列表框的拖放效果

时间:2016-12-15 03:26:54

标签: wpf powershell drag-and-drop

我将拖放操作限制为Powershell中的WPF列表框控件,只允许删除文本文件。我想使用System.Windows.DragDropEffects属性来阻止对DragEnter事件的放置操作,因为它还会更改鼠标光标,为拒绝放置操作提供用户反馈。我仍然可以通过验证Drop事件上的文件扩展名来限制对已删除文件所采取的操作。但我更愿意阻止掉落动作,以便更顺畅地进行用户交互。

在调试中我已经验证正确设置了DragDropEffect属性,但是事件处理程序似乎没有反映出更改。我相信尝试使用DragEventArgs类通过Powershell管道监视事件可能是一种限制。

WPF列表框的代码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列表框设置DragDropEffect属性按预期工作。鼠标更改并阻止丢弃事件。但是在这里,$ _管道传递的对象是System.Windows.Forms.DragEventArgs类。

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()

任何想法或建议表示赞赏!!

2 个答案:

答案 0 :(得分:0)

经过大量的Google-Foo,运行Snoop WPF监控事件以及反复试验,我意识到我只是订阅了错误的Drag事件。要实现连续显示不允许游标操作的结果,必须使用DragOver事件。

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

显然,在Powershell中使用WPF代码时,DragEnter事件仅在允许光标改回时触发,而DragOver事件在鼠标悬停在控件上时持续触发,保持显示操作不允许光标。

希望能够在一段时间内保存其他开发人员。

答案 1 :(得分:0)

通过在更改 $_.Handled = $true 后添加 $_.Effects 对我有用。

这是取自此处:https://stackoverflow.com/a/44321363/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()