57 votes

Charger une fenêtre WPF sans l'afficher

Je crée un raccourci clavier global pour afficher une fenêtre en invoquant RegisterHotKey() . Mais pour ce faire, j'ai besoin de la valeur HWND qui n'existe pas tant que la fenêtre n'est pas chargée, c'est-à-dire affichée pour la première fois. Mais je ne veux pas afficher la fenêtre avant de pouvoir définir le raccourci clavier. Existe-t-il un moyen de créer une HWND pour cette fenêtre invisible à l'utilisateur ?

71voto

Patrick Klug Points 5320

Si vous ciblez .NET 4.0, vous pouvez utiliser la nouvelle fonction EnsureHandle disponible sur le site WindowInteropHelper :

public void InitHwnd()
{
    var helper = new WindowInteropHelper(this);
    helper.EnsureHandle();
}

(merci à Thomas Levesque pour de le souligner. )

Si vous utilisez une version plus ancienne de .NET Framework, le moyen le plus simple est d'afficher la fenêtre pour accéder au HWND tout en définissant quelques propriétés pour s'assurer que la fenêtre est invisible et ne vole pas le focus :

var window = new Window() //make sure the window is invisible
{
    Width = 0,
    Height = 0,
    WindowStyle = WindowStyle.None,
    ShowInTaskbar = false,
    ShowActivated = false
};
window.Show();

Une fois que vous souhaitez afficher la fenêtre réelle, vous pouvez définir le contenu, la taille et changer le style pour revenir à une fenêtre normale.

2 votes

Oui, cela fonctionne, merci. Il n'est même pas nécessaire de définir WindowState. J'ai également défini le contenu de la fenêtre dans le XAML, mais ce n'est pas important. Une autre chose est que WindowStartupLocation=CenterScreen ne fonctionne pas correctement de cette façon, mais c'est facile à corriger.

0 votes

J'ai supprimé le setter WindowState... merci de me l'avoir signalé.

1 votes

J'ajouterais ResizeMode = ResizeMode.NoResize car il supprime la bordure de la fenêtre lors du redimensionnement.

21voto

DJP Points 91

Vous pouvez également transformer la fenêtre en une fenêtre de message uniquement. Comme ce type de fenêtre ne prend pas en charge les éléments graphiques, elle ne sera jamais affichée. En fait, il s'agit d'appeler :

    SetParent(hwnd, (IntPtr)HWND_MESSAGE);

Soit vous créez une fenêtre de message dédiée qui sera toujours cachée, soit vous utilisez la vraie fenêtre de l'interface graphique et la transformez en fenêtre normale lorsque vous souhaitez l'afficher. Voir le code ci-dessous pour un exemple plus complet.

    [DllImport("user32.dll")]
    static extern IntPtr SetParent(IntPtr hwnd, IntPtr hwndNewParent);

    private const int HWND_MESSAGE = -3;

    private IntPtr hwnd;
    private IntPtr oldParent;

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;

        if (hwndSource != null)
        {
            hwnd = hwndSource.Handle;
            oldParent = SetParent(hwnd, (IntPtr)HWND_MESSAGE);
            Visibility = Visibility.Hidden;
        }
    }

    private void OpenWindowMenuItem_Click(object sender, RoutedEventArgs e)
    {
        SetParent(hwnd, oldParent);
        Show();
        Activate();
    }

Pour moi, la solution consistant à régler la largeur et la hauteur sur zéro et le style sur aucun n'a pas fonctionné, car elle affichait toujours une fenêtre minuscule, avec une ombre gênante de ce qui semble être la bordure autour d'une fenêtre 0x0 (testé sur Windows 7). C'est pourquoi je propose cette option alternative.

1 votes

Il semble que ce soit la seule solution à 100 %.

0 votes

Merci pour ce bon conseil. Elle m'a vraiment aidé, car toutes les autres solutions proposées ici provoquaient des effets secondaires qui n'étaient pas très agréables. Mais la vôtre aussi, malheureusement. J'ai créé une fenêtre MetroWindow (en utilisant Fluent Ribbon Suite). Ensuite, la fenêtre a une bordure typique, qui n'est normalement pas visible pour ces MetroWindows... Une idée pour résoudre ce problème ?

1 votes

Parfait. Il faut juste.. : ShowActivated = false ; après Visibility, car sans cela, il clignote.

18voto

Thomas Levesque Points 141081

Il s'agit d'une astuce peu pratique, mais qui devrait fonctionner et qui n'a pas les inconvénients de la modification de l'opacité :

  • fixer le WindowStartupLocation a Manual
  • fixer le Top y Left propriétés à l'extérieur de l'écran
  • fixer ShowInTaskbar à false pour que l'utilisateur ne se rende pas compte qu'il y a une nouvelle fenêtre
  • Show y Hide la fenêtre

Vous devriez maintenant être en mesure de récupérer le HWND

EDIT : une autre option, probablement meilleure : set ShowInTaskBar à faux et WindowState a Minimized puis l'afficher : il ne sera pas visible du tout

2 votes

Avec votre autre option, je peux voir la fenêtre minimisée dans le coin inférieur gauche de l'écran. Mais la première option semble prometteuse.

0 votes

@svick : quel OS utilisez-vous ? Sous Windows 7, la fenêtre minimisée n'est pas visible.

0 votes

Ah, oui, je me souviens de ce comportement... il semble avoir changé dans Win7 (ou peut-être Vista)

11voto

Thomas Levesque Points 141081

J'avais déjà posté une réponse à cette question, mais je viens de trouver une meilleure solution.

Si vous devez simplement vous assurer que le HWND est créé, sans afficher la fenêtre, vous pouvez procéder de la manière suivante :

    public void InitHwnd()
    {
        var helper = new WindowInteropHelper(this);
        helper.EnsureHandle();
    }

(en fait, le EnsureHandle n'était pas disponible au moment où la question a été posée, elle a été introduite dans .NET 4.0)

0 votes

Il s'agit probablement de la réponse acceptée maintenant, ou dois-je mettre à jour ma réponse pour l'inclure également ? Je ne sais pas quelle est la pratique respectée pour les différences de version des frameworks.

0 votes

@PatrickKlug, je ne sais pas non plus... Vous pouvez soit l'inclure dans votre réponse, soit simplement faire référence à ma réponse, selon ce qui vous semble le mieux.

1 votes

Pouvez-vous me dire comment invoquer cette fonctionnalité ? J'ai besoin d'appeler [Window w = new Window()] pour initialiser l'objet, mais dans cette ligne même, il affiche la fenêtre, avant même d'appeler w.Show() !

5voto

Joel Cochran Points 2643

Je n'ai jamais essayé de faire ce que vous faites, mais si vous avez besoin d'afficher la fenêtre pour obtenir le HWND, mais que vous ne voulez pas montrer Cela empêchera également tout test d'impact de se produire. Ensuite, vous pourriez avoir une méthode publique sur la fenêtre pour changer l'opacité à 100 lorsque vous voulez la rendre visible.

0 votes

Malheureusement, pour que le réglage de l'opacité soit efficace, AllowsTransparency doit être réglé sur true, ce qui force WindowStyle à WindowStyle.None, ce qui n'est pas ce que je veux. De plus, AllowsTransparency ne peut pas être modifié une fois que la fenêtre est affichée, et je ne peux donc pas le rétablir par la suite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X