1
votes

FolderBrowserDialog mettre au premier plan

J'ai la fonction PowerShell suivante qui fonctionne bien, mais la fenêtre s'ouvre en arrière-plan derrière PowerShell ISE.

# Shows folder browser dialog box and sets to variable
function Get-FolderName() {
    Add-Type -AssemblyName System.Windows.Forms
    $FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog -Property @{
        SelectedPath = 'C:\Temp\'
        ShowNewFolderButton = $false
        Description = "Select Staging Folder."
    }
    # If cancel is clicked the script will exit
    if ($FolderBrowser.ShowDialog() -eq "Cancel") {break}
    $FolderBrowser.SelectedPath
} #end function Get-FolderName

Je peux voir qu'il y a un code .TopMost > propriété qui peut être utilisée avec la classe OpenFileDialog , mais cela ne semble pas être transféré vers la classe FolderBrowserDialog .

Suis-je absent?


0 commentaires

3 Réponses :


2
votes

J'espère que cela aidera

$openFileDialog1.ShowDialog((New - Object System.Windows.Forms.Form - Property @{TopMost = $true; TopLevel = $true}))

// Modifier pour commenter

Il existe 2 variantes (surcharges) de la méthode ShowDialog ().

Consultez la documentation: http://msdn.microsoft.com/en-us/library/system.windows.forms.openfiledialog.showdialog%28v=vs.110%29.aspx

Dans la seconde variante, vous pouvez spécifier la fenêtre qui devrait être la mère du dialogue.

Le plus haut doit être utilisé avec parcimonie ou pas du tout! Si plusieurs fenêtres sont les plus hautes, laquelle est la plus haute? ;-)) Essayez d'abord de définir votre fenêtre en tant que mère, puis OpenfileDialog / SaveFileDialog devrait toujours apparaître au-dessus de votre fenêtre:

$openFileDialog1.ShowDialog($form1)

Si cela ne suffit pas, prenez Topmost.

Votre fenêtre de dialogue hérite des propriétés de la mère. Si votre fenêtre mère est la plus haute, alors la boîte de dialogue est également la plus haute.

Voici un exemple qui définit le dialogue le plus haut.

Dans cet exemple, cependant, une nouvelle fenêtre non liée est utilisée , donc la boîte de dialogue n'est pas liée.

Add-Type -AssemblyName System.Windows.Forms
$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
$FolderBrowser.Description = 'Select the folder containing the data'
$result = $FolderBrowser.ShowDialog((New-Object System.Windows.Forms.Form -Property @{TopMost = $true }))
if ($result -eq [Windows.Forms.DialogResult]::OK){
$FolderBrowser.SelectedPath
} else {
exit
}


2 commentaires

Ok, j'ai donc trouvé cette méthode dans mes recherches, mais elle ne semblait pas toujours fonctionner et semblait simplement empêcher vscode d'accepter l'entrée de clé dans la console pour un appel d'informations d'identification après. J'espérais ajouter "TopMost = $ true" à ma liste de propriétés dans le code d'origine que j'ai fourni mais je ne l'aime pas et je ne vois pas pourquoi s'il peut être utilisé dans le vôtre ...?


@Jaapaap Malheureusement, votre modification concerne uniquement OpenFileDialog , pas FolderBrowserDialog



1
votes

Une manière fiable de faire ceci est d'ajouter un morceau de code C # à la fonction. Avec ce code, vous pouvez obtenir un handle Windows qui implémente l'interface IWin32Window . L'utilisation de cette poignée dans la fonction ShowDialog garantira que la boîte de dialogue est affichée en haut.

# Show an Open Folder Dialog and return the directory selected by the user.
function Get-FolderName {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
        [string]$Message = "Select a directory.",

        [string]$InitialDirectory = [System.Environment+SpecialFolder]::MyComputer,

        [switch]$ShowNewFolderButton
    )

    $browserForFolderOptions = 0x00000041                                  # BIF_RETURNONLYFSDIRS -bor BIF_NEWDIALOGSTYLE
    if (!$ShowNewFolderButton) { $browserForFolderOptions += 0x00000200 }  # BIF_NONEWFOLDERBUTTON

    $browser = New-Object -ComObject Shell.Application
    # To make the dialog topmost, you need to supply the Window handle of the current process
    [intPtr]$handle = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle

    # see: https://msdn.microsoft.com/en-us/library/windows/desktop/bb773205(v=vs.85).aspx
    $folder = $browser.BrowseForFolder($handle, $Message, $browserForFolderOptions, $InitialDirectory)

    $result = $null
    if ($folder) { 
        $result = $folder.Self.Path 
    } 

    # Release and remove the used Com object from memory
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($browser) | Out-Null
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()


    return $result
}

$folder = Get-FolderName
if ($folder) { Write-Host "You selected the directory: $folder" }
else { "You did not select a directory." }

Vous pouvez également opter pour l'utilisation du code Shell.Application > objet avec quelque chose comme ceci:

Function Get-FolderName {   
    # To ensure the dialog window shows in the foreground, you need to get a Window Handle from the owner process.
    # This handle must implement System.Windows.Forms.IWin32Window
    # Create a wrapper class that implements IWin32Window.
    # The IWin32Window interface contains only a single property that must be implemented to expose the underlying handle.
    $code = @"
using System;
using System.Windows.Forms;

public class Win32Window : IWin32Window
{
    public Win32Window(IntPtr handle)
    {
        Handle = handle;
    }

    public IntPtr Handle { get; private set; }
}
"@

    if (-not ([System.Management.Automation.PSTypeName]'Win32Window').Type) {
        Add-Type -TypeDefinition $code -ReferencedAssemblies System.Windows.Forms.dll -Language CSharp
    }
    # Get the window handle from the current process
    # $owner = New-Object Win32Window -ArgumentList ([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)
    # Or write like this:
    $owner = [Win32Window]::new([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)

    # Or use the the window handle from the desktop
    # $owner =  New-Object Win32Window -ArgumentList (Get-Process -Name explorer).MainWindowHandle
    # Or write like this:
    # $owner = [Win32Window]::new((Get-Process -Name explorer).MainWindowHandle)

    $FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog -Property @{
        SelectedPath = 'C:\Temp\'
        ShowNewFolderButton = $false
        Description = "Select Staging Folder."
    }
    # set the return value only if a selection was made
    $result = $null
    If ($FolderBrowser.ShowDialog($owner) -eq "OK") {
        $result = $FolderBrowser.SelectedPath
    }
    # clear the dialog from memory
    $FolderBrowser.Dispose()

    return $result
}

Get-FolderName


1 commentaires

Salut Theo, merci beaucoup pour votre aide et pour avoir fourni ce code. J'ai dû mettre cette exigence à la fin de la liste en raison des délais, mais je reviendrai quand je le pourrai. Toutes mes excuses pour la réponse tardive, mais cela est apprécié.



0
votes

Je viens de trouver un moyen simple d'obtenir la valeur IWin32Window de PowerShell afin que les formulaires puissent être modaux. Créez un objet System.Windows.Forms.NativeWindow et attribuez-lui le handle PowerShell.

function Show-FolderBrowser 
{       
    Param ( [Parameter(Mandatory=1)][string]$Title,
            [Parameter(Mandatory=0)][string]$DefaultPath = $(Split-Path $psISE.CurrentFile.FullPath),
            [Parameter(Mandatory=0)][switch]$ShowNewFolderButton)

    $DefaultPath = UNCPath2Mapped -path $DefaultPath; 

    $FolderBrowser = new-object System.Windows.Forms.folderbrowserdialog;
    $FolderBrowser.Description = $Title;
    $FolderBrowser.ShowNewFolderButton = $ShowNewFolderButton;
    $FolderBrowser.SelectedPath = $DefaultPath;
    $out = $null;

    $caller = [System.Windows.Forms.NativeWindow]::new()
    $caller.AssignHandle([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)

    if (($FolderBrowser.ShowDialog($caller)) -eq [System.Windows.Forms.DialogResult]::OK.value__)
    {
        $out = $FolderBrowser.SelectedPath;
    }

    #Cleanup Disposabe Objects
    Get-Variable -ErrorAction SilentlyContinue -Scope 0  | Where-Object {($_.Value -is [System.IDisposable]) -and ($_.Name -notmatch "PS\s*")} | ForEach-Object {$_.Value.Dispose(); $_ | Clear-Variable -ErrorAction SilentlyContinue -PassThru | Remove-Variable -ErrorAction SilentlyContinue -Force;}

    return $out;
}


0 commentaires