web-dev-qa-db-fra.com

Exécuter deux fenêtres Winform simultanément

J'ai deux formulaires C # winform (.NET 4.0) qui exécutent des tâches automatisées distinctes mais similaires. Séparés en ce sens qu’il s’agit de processus/flux de travail distincts, mais dont la façon de fonctionner fonctionne suffisamment pour partager les mêmes ressources (méthodes, modèles de données, assemblys, etc.) dans le projet. 

Les deux formulaires sont complets, mais je ne sais pas trop comment exécuter le programme pour que chaque fenêtre s’ouvre au lancement et s’exécute indépendamment. Le programme sera "toujours actif" lorsqu'il sera déployé.

Cela peut sembler un peu fondamental, mais la plupart de mes expériences de développement ont été réalisées avec des applications Web. Enfiler/etc est encore un peu étranger pour moi. J'ai effectué des recherches, mais la plupart des réponses que j'ai trouvées ont trait à l'interaction utilisateur et aux cas d'utilisation séquentiels - il ne s'agira que d'un seul système exécutant en permanence deux processus distincts, qui devront interagir avec le monde de manière indépendante.

Les solutions potentielles que j'ai trouvées pourraient impliquer plusieurs threads, ou peut-être une sorte de MDI, ou quelques personnes ont suggéré DockPanelSuite (bien que le fait d'être dans un environnement de super-entreprise, le téléchargement de fichiers tiers est plus facile à dire qu'à faire).

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // Rather than specifying frmOne or frmTwo,
        // load both winforms and keep them running.
        Application.Run(new frmOne());
    }
}
18
RJB

Vous pouvez créer une nouvelle ApplicationContext pour représenter plusieurs formulaires:

public class MultiFormContext : ApplicationContext
{
    private int openForms;
    public MultiFormContext(params Form[] forms)
    {
        openForms = forms.Length;

        foreach (var form in forms)
        {
            form.FormClosed += (s, args) =>
            {
                //When we have closed the last of the "starting" forms, 
                //end the program.
                if (Interlocked.Decrement(ref openForms) == 0)
                    ExitThread();
            };

            form.Show();
        }
    }
}

En utilisant cela, vous pouvez maintenant écrire:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MultiFormContext(new Form1(), new Form2()));
29
Servy

Si vous avez vraiment besoin de deux fenêtres/formulaires pour s'exécuter sur deux threads d'interface utilisateur distincts, vous pouvez faire quelque chose comme ceci:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var thread = new Thread(ThreadStart);
        // allow UI with ApartmentState.STA though [STAThread] above should give that to you
        thread.TrySetApartmentState(ApartmentState.STA); 
        thread.Start(); 

        Application.Run(new frmOne());
    }

    private static void ThreadStart()
    {
        Application.Run(new frmTwo()); // <-- other form started on its own UI thread
    }
}
9
Paul Sasik

Supposition

Vous n'avez pas besoin de deux processus différents, vous n'utilisez que les deux processus car vous voulez avoir les deux formulaires différents et vous voulez pouvoir laisser l'application en cours d'exécution jusqu'à ce que les deux formulaires soient quittés.

Une autre solution

Faites confiance au mécanisme d'événement Form.Closed. Vous pouvez ajouter un gestionnaire d'événements qui vous permet de spécifier l'action à effectuer à la fermeture d'un formulaire. Par exemple. quitte l'application lorsque les deux formulaires sont fermés.

En termes de code

    public Form1()
    {
        InitializeComponent();

        _form2 = new Form2();
        _form2.Show(this);

        this.Closed += Form1Closed;
        _form2.Closed += Form2Closed;
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        e.Cancel = true;
        Hide();
        Form1Closed(this, new EventArgs());
        base.OnFormClosing(e);
    }

    private void Form1Closed(object sender, EventArgs eventArgs)
    {
        form1IsClosed = true;

        TryExitApplication();
    }

    private void Form2Closed(object sender, EventArgs eventArgs)
    {
        _form2IsClosed = true;

        TryExitApplication();
    }

    private void TryExitApplication()
    {
        if (form1IsClosed && _form2IsClosed)
        {
            Dispose();
            Application.Exit();
        }
    }

Notez que cela devrait être refondu pour en faire une meilleure solution. 


METTRE &AGRAVE; JOUR

Les commentaires fournis par Servy m'ont incité à réviser cette "solution supposée simple", qui indiquait que sa solution était bien meilleure que cette solution. Puisque je suis aidé à laisser la réponse, je vais utiliser cette réponse, je vais également aborder les problèmes qui commencent à se poser lorsque vous choisissez cette solution: 

  • annuler des événements proches
  • réacheminement d'un événement à l'autre
  • appel de force Dispose.
  • comme Servy l'a fait remarquer: maintenance peu conviviale (indiquer le type de formulaire fermé)
1
bas