【问题标题】:Powershell script issue handling drag and drop effects for WPF listboxPowershell脚本问题处理WPF列表框的拖放效果
【发布时间】:2016-12-15 03:26:54
【问题描述】:

我将拖放操作限制为 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 属性按预期工作。鼠标发生变化并阻止了 drop 事件。但是这里,$_ 管道中传递的对象属于 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()

感谢任何想法或建议!

【问题讨论】:

    标签: wpf powershell drag-and-drop


    【解决方案1】:

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

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

    显然,当在 Powershell 中使用 WPF 代码时,DragEnter 事件只触发一次,允许光标变回,而 DragOver 事件在鼠标悬停在控件上时会持续触发,以保持操作不允许光标的显示。

    希望这能够为其他开发人员节省一些时间。

    【讨论】:

    • 嗨,这对我不起作用。它仍然显示拖动的叠加层。效果改变后需要用$_.Handled = $true修复。
    【解决方案2】:

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

    取自这里: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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多