2009-03-04 11 views
2

J'ai une application qui a un formulaire principal et utilise un gestionnaire d'événements pour traiter les données entrantes et refléter les changements dans les différents contrôles sur le formulaire principal. Cela fonctionne bien.Écoute d'événements dans un formulaire principal à partir d'un autre formulaire en C#

J'ai aussi une autre forme dans l'application. Il peut y avoir plusieurs instances de ce second formulaire en cours d'exécution à un moment donné. Ce que je voudrais faire est que chaque instance de cette seconde forme écoute le gestionnaire d'événements dans le formulaire principal et met à jour les contrôles sur son instance du second formulaire.

Comment est-ce que je ferais ceci?

Voici un exemple de code. Je veux des informations du gestionnaire d'événements the_timer_Tick pour mettre à jour chaque instance de SecondaryForm.

public partial class Form1 : Form 
{ 
    Timer the_timer = new Timer(); 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     the_timer.Tick += new EventHandler(the_timer_Tick); 
     the_timer.Interval = 2000; 
     the_timer.Enabled = true; 
    } 

    void the_timer_Tick(object sender, EventArgs e) 
    { 
     // I would like code in here to update all instances of SecondaryForm 
     // that happen to be open now. 
     MessageBox.Show("Timer ticked"); 
    } 

    private void stop_timer_button_Click(object sender, EventArgs e) 
    { 
     the_timer.Enabled = false; 
    } 

    private void start_form_button_Click(object sender, EventArgs e) 
    { 
     SecondaryForm new_form = new SecondaryForm(); 
     new_form.Show(); 
    } 
} 

Répondre

5
class SecondForm 
{ 
    private FirstForm firstForm; 

    public SecondForm() 
    { 
    InitializeComponent(); 
    // this means unregistering on form closing, uncomment if is necessary (anonymous delegate) 
    //this.Form_Closing += delegate { firstForm.SomeEvent -= SecondForm_SomeMethod; }; 
    } 

    public SecondaryForm(FirstForm form) : this() 
    { 
    this.firstForm = form; 
    firstForm.Timer.Tick += new EventHandler(Timer_Tick); 
    } 

    // make it public in case of external event handlers registration 
    private void Timer_Tick(object sender, EventArgs e) 
    { 
    // now you can access firstForm or it's timer here 
    } 
} 

class FirstForm 
{ 
    public Timer Timer 
    { 
    get 
    { 
     return this.the_timerl 
    } 
    } 

    public FirstForm() 
    { 
    InitializeComponent(); 
    } 

    private void Button_Click(object sender, EventArgs e) 
    { 
    new SecondForm(this).ShowDialog(); // in case of internal event handlers registration (in constructor) 
    // or 
    SecondForm secondForm = new SecondForm(this); 
    the_timer.Tick += new EventHandler(secondForm.Timer_tick); // that method must be public 
    } 
+0

N'oubliez pas de supprimer le gestionnaire d'événements lorsque le second formulaire est fermé, sinon vous risquez d'avoir une fuite de référence ... –

+0

Toutes vos références à SecondForm ne devraient-elles pas être de type SecondaryForm? Et à quoi ressemblerait SomeEvent dans le formulaire principal que j'ai posté? – Dave

+0

Oui, je veux dire SecondForm = SecondaryForm. Par exemple, vous pouvez rendre Timer publique ou créer une propriété pour y accéder, et ne pas écouter les événements FistForm, mais ses événements timer: Voir mon code, je vais l'éditer – abatishchev

0

Je suppose que vous pouvez faire SecondaryForm prendre la forme mère dans le constructeur, et ajouter un gestionnaire d'événements dans le constructeur.

private void start_form_button_Click(object sender, EventArgs e) 
{ 
    SecondaryForm new_form = new SecondaryForm(this); 
    new_form.Show(); 
} 

En SecondaryForm.cs:

public SecondaryForm(ISomeView parentView) 
{ 
    parentView.SomeEvent += ..... 
} 
2

Tenir compte en utilisant des événements faiblement couplés. Cela vous permettra de coupler les classes de telle sorte qu'elles ne doivent jamais être directement conscientes l'une de l'autre. Le bloc d'application Unity est livré avec une extension appelée EventBroker qui rend ceci très simple.

Voici un petit coup de langue du sucre:

public static class EVENTS 
{ 
    public const string UPDATE_TICKED = "event://Form1/Ticked"; 
} 

public partial class Form1 : Form 
{ 
    [Publishes(EVENTS.UPDATE_TICKED)] 
    public event EventHandler Ticked; 

    void the_timer_Tick(object sender, EventArgs e) 
    { 
     // I would like code in here to update all instances of SecondaryForm 
     // that happen to be open now. 
     MessageBox.Show("Timer ticked"); 
     OnTicked(); 
    } 

    protected virtual void OnTicked() 
    { 
     if (Ticked == null) return; 
     Ticked(this, e); 
    } 
} 

public partial class SecondaryForm : Form 
{ 
    [SubscribesTo(EVENTS.UPDATE_TICKED)] 
    private void Form1_Ticked(object sender, EventHandler e) 
    { 
     // code to handle tick in SecondaryForm 
    } 
} 

Maintenant, si vous construisez ces deux classes en utilisant l'unité, ils seront automatiquement câblés ensemble.

Mise à jour

solutions plus récents utilisent le bus de messages pour gérer les événements faiblement couplés. Voir http://masstransit-project.com/ ou http://nimbusapi.github.io/ comme exemples.

+0

@ Okuma.Scott Fourni un autre lien, plus une mise à jour sur la façon dont je gère les événements faiblement couplés maintenant. Je préfère le bus de messages à la mémoire. Cela permet une échelle horizontale. Nimbus utilise Azure Message Bus et Mass Transit utilise RabbitMQ. –

Questions connexes