2
votes

Remplacement de ShowDialog () par Show ()

J'ai un formulaire qui est affiché en utilisant ShowDialog (), donc c'est une fenêtre modale.

public partial class MyMainForm : XtraForm
{
       private MyForm testForm;

       private void OpenForm(object sender, ItemClickEventArgs e)
        {
            if(testForm == null)
            {
                testForm = new MyForm();
            }
            ...
            testForm.FormClosed += testForm_Closed;
            testForm.Show(this);
        }

        private void testForm_Closed(object sender, EventArgs args)
        {
            var testForm = (Form)sender;
            testForm.Closed -= testForm_Closed;

            if (testForm.DialogResult == DialogResult.OK)
            {
               // do some stuff 1
            }
        }
 }

Il y a un bouton "OK" sur le formulaire. Lorsque vous cliquez sur OK, DialogOk est défini sur true. Dans la classe MyForm:

public partial class MyMainForm : XtraForm
{
   private MyForm testForm;

   private void OpenForm(object sender, ItemClickEventArgs e)
    {
        if(testForm == null)
        {
            testForm = new MyForm();
        }
        ...
        testForm.Enabled = true;
        testForm.FormClosed += (s, a) => {
            var dialogOk = testForm.DialogOk;
            if (dialogOk)
            {
                // do some stuff 1
            }
        };
        testForm.Show(this);
    }
}

J'ai besoin de convertir cela en une fenêtre non modale. La solution semble être d'utiliser Show () au lieu de ShowDialog (), mais quand j'utilise Show (), le code ne s'arrête pas et n'attend pas que le bouton OK soit cliqué, donc "do some stuff 1" n'est jamais appelé.

En utilisant Show (), comment puis-je conserver le comportement pour que "do some stuff 1" s'exécute après avoir cliqué sur le bouton OK?

Mise à jour: voici ce que je J'essaye maintenant:

public partial class MyForm: XtraForm
{
   public bool DialogOk;

   private void OkClick(object sender, EventArgs e)
   {
      // do some stuff 2
      ... 
      DialogOk = true;
      Close();
   }
}

Méthode 1:

private void OkClick(object sender, EventArgs e)
{
   // do some stuff 2
   ... 
   DialogOK = true;
   Hide();
}

Méthode 2:

private void OpenForm(object sender, ItemClickEventArgs e)
{
    MyForm testForm = new MyForm();
    ...
    testForm.Enabled = true;
    testForm.ShowDialog(this);
    var dialogOk = testForm.DialogOK;
    if(dialogOk)
    {
       //do some stuff 1
    }
}


7 commentaires

Une façon consiste à faire en sorte que le formulaire de dialogue appelle une méthode ou un événement dans le formulaire parent (qui lui a été passé en tant qu'argument) lorsque OkClick est cliqué.


Je suis confus. Pouvez-vous expliquer pourquoi vous avez besoin d'une fenêtre non modale pour se comporter comme une fenêtre modale? Il semble que vous devriez garder la fenêtre modale.


Puisque vous voulez verrouiller l'exécution de l'interface principale jusqu'à ce que le bouton OK soit cliqué sur la deuxième fenêtre, il me semble que ce dont vous avez besoin est en fait une fenêtre modale.


@GabrielLuci J'ai besoin de pouvoir cliquer sur d'autres fenêtres en dehors de la fenêtre modale actuelle.


BTW, Form ont une propriété appelée DialogResult - définissez-le sur DialogResult.Ok et il masquera automatiquement le formulaire et renverra la valeur - donc votre le code passe à if (testForm.ShowDialog (this) == DialogResult.Ok)


@lzzydy Je suppose que cela a du sens. Ensuite, vous devrez déplacer le code qui doit s'exécuter après la fermeture de la fenêtre. L'une ou l'autre des deux réponses ci-dessous fonctionnera.


@lzzydy vérifie ma réponse suggérée en utilisant Task et async-await.


4 Réponses :


3
votes

Vous pouvez gérer l'événement Form.Closed :

MyForm testForm = new MyForm();
testForm.Closed += testForm_Closed;
testForm.Show();

private void testForm_Closed(object sender, EventArgs args)
{
    var testForm = (Form)sender;
    testForm.Closed -= testForm_Closed;

    if (testForm.DialogResult == OK)
        // do some stuff 1
}


5 commentaires

Lorsque je clique sur OK sur le formulaire, OkClick () est toujours appelé, mais testForm_Closed n'est pas appelé. Pensez-vous que je manque quelque chose?


vous devrez appeler Close () au lieu de Hide () pour que l'événement .Closed se produise


@ pm101 J'ai changé Hide () en Close () mais l'événement ne se produit toujours pas.


Hmm, j'ai fait un exemple de projet qui fonctionne bien. Pouvez-vous mettre à jour votre code sur la question pour nous montrer ce que vous faites de nouveau?


@ pm101 J'ai mis à jour le code. J'ai essayé d'utiliser la méthode dans ce commentaire et celle ci-dessous. Les deux ont eu les mêmes résultats, où le délégué n'était pas appelé.



1
votes

Le moyen le plus simple est de déplacer le code de OpenForm vers le gestionnaire d'événements OkClick . Cependant, si ce n'est pas un bon endroit pour mettre le code car vous pourriez vouloir utiliser le même formulaire pour différentes tâches, vous pouvez ajouter un gestionnaire pour l'événement FormClosed , qui est appelé après que le formulaire est fermé et exécute le code, par exemple:

private void OpenForm(object sender, ItemClickEventArgs e)
{
    MyForm testForm = new MyForm();
    ...
    testForm.Enabled = true;
    testForm.FormClosed += (s, a) => {
      var dialogOk = testForm.DialogOK;
      if(dialogOk)
      {
         //do some stuff 1
      }
    };
    testForm.Show(this);
}


6 commentaires

Lorsque j'essaie de faire cela, j'obtiens l'erreur suivante: "Un paramètre local nommé 'sender' ne peut pas être déclaré dans cette portée car ce nom est utilisé dans une portée locale englobante pour définir un local ou un paramètre"


Cela signifie qu'il existe déjà un paramètre nommé sender sur la méthode englobante. J'ai changé le code pour n'utiliser que s et a comme noms de paramètres pour le délégué afin qu'il n'y ait plus de conflits.


Merci pour la clarification. Avec cette modification de code, le gestionnaire d'événements FormClosed n'est pas déclenché lorsque je clique sur OK ou si je ferme le formulaire. Y a-t-il autre chose qui me manque peut-être ici?


Au lieu de masquer le formulaire, vous devez le fermer à la place. Ou souhaitez-vous utiliser à nouveau la même instance plus tard?


Je n'ai pas besoin d'utiliser la même instance. Changer Hide () en Close () ne résout pas non plus le problème.


Je viens de vérifier le code dans un projet de test et le délégué a été appelé après avoir appelé Close ou en utilisant le X pour fermer le formulaire. Il doit donc y avoir une différence.



0
votes

Vous pouvez utiliser un gestionnaire d’événement asynchrone lié à un TaskCompletionSource qui écoute et attend la fermeture du formulaire

public partial class MyForm: XtraForm {

    //...

    private void OkClick(object sender, EventArgs e) {
        // do some stuff 2
        // ... 

        DialogResult = DialogResult.Ok;
        Cose();
    }
}

Avec cela, vous pouvez conserver la logique dans OpenForm et permettre au code d'attendre sans blocage.

Dans le formulaire lorsque vous cliquez sur le bouton, tout ce que vous avez à faire est de définir le résultat de la boîte de dialogue et fermez le formulaire.

private asyc void OpenForm(object sender, ItemClickEventArgs e) {
    var source = new TaskCompletionSource<DialogResult>();

    EventHandler handler = null;
    handler = (s, args) => { 
        var  form = (MyForm)s;
        form.FormClosed -= handler;
        source.SetResult(form.DialogResult);
    }

    var testForm = new MyForm();
    testForm.FormClosed += handler; //subscribe
    //...
    testForm.Enabled = true;
    testForm.Show();

    var dialogOk = await source.Task;
    if(dialogOk == DialogResult.Ok) {
       //do some stuff 1
    }
}


0 commentaires

0
votes

Cela fonctionne pour moi, donc je ne sais pas pourquoi ce n'est pas pour vous (tête de grattage) ... Ce formulaire a deux boutons, un qui ouvre à nouveau le même formulaire et un autre bouton qui ferme le formulaire. Le formulaire "parent" ajoute un événement à l'événement Closed.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form1 test = new Form1();

        test.FormClosed += Test_FormClosed;

        test.Show();
    }

    private void Test_FormClosed(object sender, FormClosedEventArgs e)
    {
        MessageBox.Show("closed -- do something else here!");
    }

    private void button2_Click(object sender, EventArgs e)
    {
        Close();
    }
}


0 commentaires