2008-10-02 9 views
10

Est-il possible que le formulaire principal puisse intercepter les événements qui déclenchent un sous-contrôle sur un contrôle utilisateur?Comment récupérer des événements à partir de sous-contrôles sur un contrôle utilisateur dans une application WinForms?

J'ai un contrôle utilisateur personnalisé intégré dans le formulaire principal de mon application. Le contrôle contient divers sous-contrôles qui manipulent des données, lui-même affiché par d'autres contrôles sur le formulaire principal. Ce que j'aimerais, c'est que le formulaire principal puisse être en quelque sorte informé lorsque l'utilisateur change de sous-contrôle, afin que je puisse mettre à jour les données et l'affichage correspondant ailleurs.

En ce moment, je triche. J'ai un délégué branché à l'événement de mise au point des sous-contrôles. Ce délégué modifie une propriété du contrôle utilisateur que je n'utilise pas ailleurs (dans cette cause, CausesValidation). J'ai alors un délégué défini sur le formulaire principal pour quand la propriété CausesValidation du contrôle d'utilisateur change, qui dirige alors l'application pour mettre à jour les données et l'affichage. Un problème survient parce que j'ai aussi un délégué mis en place quand le focus quitte le contrôle de l'utilisateur, parce que je dois valider les champs dans le contrôle utilisateur avant que je puisse permettre à l'utilisateur de faire autre chose. Cependant, si l'utilisateur ne fait que basculer entre les sous-contrôles, je ne veux pas valider, car il se peut qu'ils ne soient pas modifiés.

Fondamentalement, je veux que les données à mettre à jour lorsque l'utilisateur bascule sous-contrôles OU laisse le contrôle de l'utilisateur, mais pas valider. Lorsque l'utilisateur quitte le contrôle, je veux mettre à jour et valider. À l'heure actuelle, laisser le contrôle utilisateur déclenche deux fois la validation.

+0

Quel est le problème de lier la forme principale aux différents événements des contrôles? Il ya une tonne d'événements qui tirent pour la plupart des contrôles winform – Sekhat

+0

Je pense que je ne comprends pas ce que vous voulez réaliser: P – Sekhat

+0

Pour répondre à la première question, à travers le concepteur (qui est ce que je, relativement nouveau à C#, utilisait pour mon édition de GUI), mon formulaire a seulement accès aux événements soulevés par le contrôle de l'utilisateur, et non ses sous-contrôles. Ce dont j'ai oublié de me souvenir, c'est que je peux déclencher mes propres événements et les gérer. –

Répondre

15

La meilleure pratique consiste à exposer les événements sur le UserControl qui font apparaître les événements dans le formulaire parent. Je suis allé de l'avant et mis en place un exemple pour vous. Voici une description de ce que cet exemple fournit.

  • UserControl1
    • Créer une UserControl avec TextBox1
    • Inscrivez-vous un événement public sur le UserControl appelé ControlChanged
    • Dans le UserControl enregistrer un gestionnaire d'événements pour l'TextBox1 TextChangedEvent
    • Dans le gestionnaire TextChangeEvent fonction que j'appelle leévénementà bulles à la forme mère
  • Form1
    • déposer une instance de UserControl1 sur le concepteur
    • Enregistre un gestionnaire d'événements sur UserControl1 pour MouseLeave et ControlChanged

Voici une capture d'écran illustrant que l'événement ControlChanged que j'ai défini sur le UserControl est disponible via l'UX dans Visual Studio sur le formulaire Windows parent.

Event Handlers for User Control http://friendfeed.s3.amazonaws.com/0d5a3968cb785625c8afb3974a8d84894c476291

+0

Merci, c'est ce que j'ai fini par faire, sauf qu'au lieu de MouseLeave, j'ai utilisé FocusLeave, car potentiellement une erreur à chaque fois que l'utilisateur bouge, sa souris pourrait devenir irritante. En outre, merci de passer par tout le travail pour cela! –

+0

donc si vous avez beaucoup de contrôles différents (disons, une zone de texte, un bouton, une case à cocher et une étiquette), et que tous les événements appropriés/réels de ce contrôle sont gérés dans le contrôle utilisateur (contrôle utilisateur autonome), et vous vouliez faire exploser un événement unique (par exemple, MyControl.OnClick) dans le formulaire de conteneur, pourriez-vous "détourner" tous les événements de sous-contrôle via une seule méthode/mécanisme pour augmenter l'événement Click simple, ou devrez-vous câbler manuellement chaque événement de sous-contrôle et gérer le bouillonnement vous-même pour chacun? – MaxOvrdrv

+1

Le lien ne fonctionne pas. Code devrait aller comme texte dans la réponse, pas comme un lien pour télécharger un fichier zip. – ardila

2

Le meilleur modèle pour ce genre de chose sera de créer des événements personnalisés sur votre contrôle utilisateur, et de les élever aux moments appropriés.

Votre scénario est assez complexe, mais pas inouï. (Je suis en fait dans un mode très similaire sur un de mes projets actuels.) La façon dont je l'approche est que le contrôle de l'utilisateur est responsable de sa propre validation. Je n'utilise pas CausesValidation; au lieu du point de contrôle utilisateur approprié, j'effectue une validation via un remplacement de ValidateChildren(). (Cela se produit généralement lorsque l'utilisateur clique sur "Enregistrer" ou "Suivant" sur le contrôle utilisateur, pour moi.)

N'étant pas familier avec votre interface utilisateur de contrôle utilisateur, cela peut ne pas être 100% la bonne approche pour vous. Cependant, si vous déclenchez des événements personnalisés (éventuellement avec un événement EventArgs personnalisé qui spécifie si vous souhaitez effectuer ou non la validation), vous devriez être en mesure d'obtenir où vous voulez être.

2

Vous aurez besoin de câbler les événements que vous aimez capturer l'intérieur de votre contrôle utilisateur, et les publier dans des propriétés d'événements personnalisés sur le contrôle de l'utilisateur lui-même. Un exemple simple serait enveloppait un bouton événement click:

// CustomControl.cs 
// Assumes a Button 'myButton' has been added through the designer 

// we need a delegate definition to type our event 
public delegate void ButtonClickHandler(object sender, EventArgs e); 

// declare the public event that other classes can subscribe to 
public event ButtonClickHandler ButtonClickEvent; 

// wire up the internal button click event to trigger our custom event 
this.myButton.Click += new System.EventHandler(this.myButton_Click); 
public void myButton_Click(object sender, EventArgs e) 
{ 
    if (ButtonClickEvent != null) 
    { 
    ButtonClickEvent(sender, e); 
    } 
} 

Ensuite, dans le formulaire qui utilise ce contrôle, vous câbler l'événement comme vous le feriez pour tout autre:

// CustomForm.cs 
// Assumes a CustomControl 'myCustomControl' has been added through the desinger 
this.myCustomControl.ButtonClickEvent += new System.EventHandler(this.myCustomControl_ButtonClickEvent); 
myCustomControl_ButtonClickEvent(object sender, EventArgs e) 
{ 
    // do something with the newly bubbled event 
} 
+0

Peut-être que je me trompe ou je ne comprends pas vraiment l'idée, mais ne devrait pas y avoir ' new MyProject.CustomControl.ButtonClickHandler() 'au lieu de' new System.EventHandler() 'dans' CustomForm.cs'? – MRM

0

Je voudrais Carillon, comme décrit, il semble effectivement que vous êtes à la poursuite d'un hareng rouge. Bien qu'il semble que vous ayez une situation où le manque d'événement qui bouillonne dans WinForms vous cause des problèmes, la réalité est qu'une architecture médiocre vous oblige à avoir besoin d'un événement bouillonnant alors que vous ne devriez pas. Si vous pouvez refactoriser/restructurer votre conception de sorte que les contrôles fonctionnent avec un modèle de données commun (MVC/MVP sont des choix évidents), vous pouvez simplement appliquer des modèles WinForms courants comme les événements PropertyChanged sur le modèle pour indiquer votre formulaire principal et tout autre contrôle qui utilise ces données pour se mettre à jour. En bref, les autres réponses sont raisonnables dans la mesure où elles répondent à la question posée. Mais d'un point de vue de la qualité du code, je pense que la meilleure réponse est de séparer vos données de l'interface utilisateur.

1

Si quelqu'un se demande encore comment simuler le bouillonnement d'événement dans WinForm, la méthode Application.AddMessageFilter est un bon endroit à regarder. En utilisant cette méthode, vous pouvez installer votre propre filtre qui surveille tous les messages en cours d'affichage dans la file d'attente des messages du thread en cours.

Vous devez savoir que les messages envoyés (non publiés) ne peuvent pas être traités par ce filtre.Foutounatly, les événements les plus intéressants (comme les événements de clic) sont affichés et non envoyés et peuvent donc être surveillés par ce filtre