web-dev-qa-db-fra.com

Comment afficher la forme devant en C #

Gens,

S'il vous plaît, est-ce que quelqu'un sait comment afficher un formulaire à partir d'une application par ailleurs invisible, et le mettre en évidence (c'est-à-dire apparaître au-dessus d'autres fenêtres)? Je travaille dans C # .NET 3.5.

Je suppose que j'ai pris "complètement la mauvaise approche" ... Je fais pas _ ​​Application.Run (new TheForm ())} _ à la place je (new TheForm ()). ()... Le formulaire est fondamentalement un dialogue modal, avec quelques cases à cocher; une zone de texte et les boutons OK et Annuler. L'utilisateur coche une case et saisit une description (ou autre), puis appuie sur OK, le formulaire disparaît et le processus lit l'entrée saisie par l'utilisateur à partir du formulaire, le supprime et poursuit le traitement.

Cela fonctionne, sauf lorsque le formulaire est affiché, il ne reçoit pas le focus, il apparaît derrière l'application "Hôte", jusqu'à ce que vous cliquiez dessus dans la barre des tâches (ou autre chose). C’est un comportement très ennuyeux, qui, je le prédis, causera de nombreux "appels de support", et la version existante de VB6 n’a pas ce problème, je retourne en arrière en termes de convivialité ... et les utilisateurs ne l’accepteront pas ils ne devraient pas non plus).

Alors ... je commence à penser que je dois repenser tout le Shebang ... Je devrais montrer le formulaire à l'avance, en tant qu '"application normale" et attacher le reste du traitement à l'événement OK-button-click. Cela devrait fonctionner, mais cela prendra du temps que je n’ai pas (j’ai déjà dépassé mon temps/mon budget) ... donc je dois d’abord essayer de faire fonctionner l’approche actuelle ... même en faisant vite et bien. méthodes sales. 

Alors s'il vous plaît, est-ce que quelqu'un sait comment "forcer" un formulaire .NET 3.5 (par des moyens équitables ou des oiseaux) pour obtenir le focus? Je pense "magique" appels API Windows (je sais

Twilight Zone: Cela ne semble être un problème au travail, nous utilisons Visual Studio 2008 sur Windows XP SP3 ... Je viens tout juste de ne pas reproduire le problème avec un SSCCE (voir ci-dessous) à la maison sur Visual C # 2008 sur Vista Ulimate ... Cela fonctionne bien. Hein? WTF? 

En outre, je jurerais que le travail hier a montré la forme quand j'ai exécuté l'EXE, mais pas quand F5'ed (ou Ctrl-F5'ed) directement à partir de IDE (que je viens de supporter). .. À la maison, le formulaire montre bien de toute façon. Totalement confuster!

Cela peut être pertinent ou non, mais Visual Studio s'est écrasé et a brûlé ce matin alors que le projet fonctionnait en mode débogage et en modifiant le code "à la volée" ... cela s'est bloqué, ce que je présumais être une boucle d'erreur sans fin. messages. Le message d'erreur concernait "Je ne peux pas déboguer ce projet car il ne s'agit pas du projet actuel, ou de quelque chose ... Je viens de l'assommer avec le processus Explorer. Il a redémarré correctement et a même proposé de récupérer le fichier" perdu ". "file, une offre que j’ai acceptée.

using System;
using System.Windows.Forms;

namespace ShowFormOnTop {
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            Form1 frm = new Form1();
            frm.ShowDialog();
        }
    }
}

Background: Je porte une implémentation VB6 existante vers .NET ... C'est un "plugin" pour une application SIG "client" appelée MapInfo . Le client existant "travaillait de manière invisible" et mes instructions étaient "de garder la nouvelle version aussi proche que possible de l'ancienne version", ce qui fonctionne assez bien (après des années de correction); il vient juste d’être écrit dans une langue non supportée, nous devons donc le porter.

À propos de moi: Je suis plutôt un adepte des langages C # et .NET en général, bien que je possède un certificat d'essuyage des fonds, je suis un programmeur professionnel depuis 10 ans; Donc, je sais en quelque sorte "connaître certaines choses".

Toute idée serait la bienvenue ... et merci à tous d'avoir pris le temps de lire jusque-là. La consistance n'est pas (apparemment) mon fort. 

À votre santé. Keith.

21
corlettk

Simplement

yourForm.TopMost = true;
47
cablehead

Il y a une surcharge de Form.ShowDialog () qui prend un objet IWin32Window. Ce IWin32Window est traité comme la fenêtre parente du formulaire.

Si vous avez la fenêtre parent en tant que System.Windows.Forms.Form, continuez et passez-la simplement. Sinon, récupérez le HWND (peut-être par P/Invoking to FindWindow ()) et créez une implémentation factice IWin32Window qui renvoie simplement le HWND ( Plus de détails ).

4
ChrisV
  1. Vous avez dit que cela fonctionne bien lorsque vous utilisez Application.Run. Pourquoi ne voulez-vous pas utiliser Application.Run, alors?
  2. Avez-vous essayé d'appeler BringToFront() depuis OnLoad ou OnShown?
3
P Daddy

Form.Activate() a travaillé dans mon cas.

3
Esen

C'est la solution finale que j'ai écrite après 20 tentatives différentes:

/* A workaround for showing a form on the foreground and with focus,
 * even if it is run by a process other than the main one
 */
public static void ShowInForeground(this Form form, bool showDialog = false)
{
    if (showDialog)
    {
        //it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
        form.WindowState = FormWindowState.Minimized;
        form.Shown += delegate(Object sender, EventArgs e) {
            ((Form)sender).WindowState = FormWindowState.Normal;
        };
        form.ShowDialog();
    }
    else
    {
        //it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
        form.WindowState = FormWindowState.Minimized;
        form.Show();
        form.WindowState = FormWindowState.Normal;

        //set focus on the first control
        form.SelectNextControl(form.ActiveControl, true, true, true, true);
    }
}
2
bluish

Je l'ai piraté à partir d'une application sur laquelle je travaille. Nous avons une grande application qui charge une série de modules écrits par différentes équipes. Nous avons écrit l'un de ces modules et nous devions ouvrir une boîte de dialogue de connexion pendant cette initialisation. Il a été défini sur '.TopMost = true', mais cela n'a pas fonctionné.

Il utilise le WindowsFormsSynchronizationContext pour ouvrir une boîte de dialogue, puis récupère le résultat de la boîte de dialogue.

Je fais rarement du codage avec une interface graphique, et je soupçonne que c'est peut-être excessif, mais cela pourrait aider quelqu'un s'il est bloqué. J'ai eu du mal à comprendre comment l'état est passé à SendOrPostCallback, car tous les exemples que je pouvais trouver ne l'utilisaient pas.

En outre, cela provient d'une application en cours d'utilisation, mais j'ai supprimé plusieurs bits de code et modifié certains détails. Toutes mes excuses s'il ne compile pas. 

public bool Dummy()
{

// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();

// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
    // We are in the main thread. Just display the dialog
    DialogResult result = myDialog.ShowDialog();
    return result == DialogResult.OK;
}
else
{
    // Get the window handle of the main window of the calling process
    IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;

    if (windowHandle == IntPtr.Zero)
    {
        // No window displayed yet
        DialogResult result = myDialog.ShowDialog();
        return result == DialogResult.OK;
    }
    else
    {
        // Parent window exists on separate thread
        // We want the dialog box to appear in front of the main window in the calling program
        // We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
        object resultState = null;
        WindowsFormsSynchronizationContext.Current.Send(
            new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);

        if (resultState is DialogResult)
        {
            DialogResult result = (DialogResult) resultState;
            return result == DialogResult.OK;
        }
        else
            return false;

    }
}

}

1
alex

Activate() a également travaillé pour moi.

BringToFront() n'a rien fait dans ce cas, je ne sais pas pourquoi.

1
user2162266

Cela a parfaitement fait le travail:

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
0
Willie Bronkhorst

J'ai un code dans le projet.

private static extern bool SetForegroundWindow(
IntPtr hWnd); 
public static void ShowToFront(Form form)
{
    FormWindowState oldState = form.WindowState;
    form.WindowState = FormWindowState.Minimized;
    form.Show();

    form.Activate();
    form.TopLevel = false;
    form.TopLevel = true;
    form.SelectNextControl(form.ActiveControl, true, true, true, true);
    SetForegroundWindow(form.Handle);
    form.Focus();
    form.WindowState = oldState;
}
0
phuong

Il semblerait que ce comportement soit spécifique à XP ... Je ne peux donc pas le reproduire sous Vista.

http://www.gamedev.net/community/forums/topic.asp?topic_id=218484

EDIT: PS: C'est l'heure de me coucher (2 heures du matin ;-).

Merci à tous pour vos réponses ... il y a un "peu de choses" que je peux essayer ... Je pourrais même aller au bureau demain pour les essayer ... Oui, oui ... J'ai eu une vie une fois, mais je l'ai échangée pour une coupe de cheveux et un travail ;-)

Salut à tous. Keith.

0
corlettk