2010-11-21 15 views
5

J'ai un WPF UserControl dans lequel je tente de mettre en œuvre la mesure MouseClick (car il n'y a pas événement MouseClick sur WPF (utilisateur) Contrôle) événement.« System.StackOverflowException » est produite dans PresentationCore.dll

j'obtenu ce qui suit:

alt text

Certains code:

/// <summary> 
/// Occurs when users left clicks the MyControl. 
/// </summary> 
public event MouseButtonEventHandler MouseClick { add { AddHandler(MouseClickEvent, value); } remove { RemoveHandler(MouseClickEvent, value); } } 

    protected virtual void OnMouseClick(MouseButtonEventArgs e) 
    { 
     base.RaiseEvent(e); 
     //this.RaiseEvent(new RoutedEventArgs(MouseClickEvent, this)); 
    } 

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
    { 
     base.OnMouseLeftButtonUp(e); 
     if (!this.movedAfterMouseDown) 
     { 
      OnMouseClick(e); 
     } 
     this.gotLeftButtonDown = false; 
     this.movedAfterMouseDown = false; 
    } 

Alors, où est le problème?

MISE À JOUR 1

protected virtual void OnMouseClick(MouseButtonEventArgs e) 
{ 
    //base.RaiseEvent(e); 
    MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton); 
    this.RaiseEvent(args); 
} 

valeur ne peut pas être nulle. Nom du paramètre: RoutedEvent

alt text

MISE À JOUR 2

Un autre événement personnalisé Je mis en œuvre avec succès (travail sans problèmes) - SelectedChanged:

static void OnIsSelectedChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
{ 
    var s = (MyControl)source; 

    s.RaiseEvent(new RoutedEventArgs(SelectedChangedEvent, s)); 
} 

MISE À JOUR 3

système. Implémentation OnPreviewMouseDoubleClick de Windows.Controls.Control:

protected virtual void OnPreviewMouseDoubleClick(MouseButtonEventArgs e) 
{ 
    base.RaiseEvent(e); 
} 

Mise à jour 5 (pour les personnes dans le réservoir)

class Foo : FrameworkElement 
{ 
    event EasterCameEvent; // I named it MouseClick 

    public DoSomething() 
    { 
     EasterCameArgs args= ... 

     if (Date.Now = EasterDate) 
      OnEasterCame(args) 
    } 

    protected virtual void OnEasterCame(EasterCameArgs e) 
    { 
     base.RaiseEvent(e); 
    } 
} 
+0

+1 pour le titre contenant SO. – Moshe

Répondre

3
protected virtual void OnMouseClick(MouseButtonEventArgs e) 
{ 
    MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton); 

    // Don't forget this 
    args.RoutedEvent = MouseClickEvent; 

    base.RaiseEvent(args); 
} 
+0

Alors, ça * se * re-relançait encore et encore? En définissant la propriété routedevent, vous déclenchez un événement complètement différent plutôt que le même. –

+0

@Josh: cela n'augmentera l'événement qu'une seule fois: 'base.RaiseEvent (args);' base.RaiseEvent n'appelle jamais OnMouse, car il ne connaît pas son existence. – serhio

+0

Nous parlons de deux choses complètement différentes. Mon problème n'était pas avec cette méthode ici. C'était avec le gestionnaire OnLeftButtonUp. Cela appelle OnMouseClick qui à son tour appelle à nouveau OnLeftButtonUp. Vous avez peut-être résolu le problème, mais comprenez-vous pourquoi cela s'est brisé? –

2

Je pense qu'il est dans cette ligne:

base.RaiseEvent(e); 

Si vous manipulez la souris clic, vous ne voulez pas relancez l'événement car cela appellera simplement votre gestionnaire de nouveau, ce qui soulèvera l'événement ....

+1

Au lieu de 'base.RaiseEvent (e)', vous devriez probablement utiliser 'base.OnMouseClick (e)'. BTW, je crois que vous devriez être en mesure de jeter un oeil à certains de la pile d'appels dans le débogueur pour voir les appels récursifs. –

+0

@Colin Thomsen: e ... homme, il n'y a pas de base.OnMouseClick dans un UserControl WPF. C'est pourquoi j'en ai déclaré un dans mon événement personnalisé «MouseClick». – serhio

+0

@serhio - Qu'est-ce que vous essayez d'atteindre en re-relançant l'événement? – ChrisF

3

Vous devez supprimer le base.RaiseEvent (e) de TOUTES les parties de votre contrôle utilisateur personnalisé. C'est la cause du débordement de la pile.

Si vous héritez de UserControl, les événements de clic sont déjà implémentés pour vous. Vous n'avez pas besoin de ré-implémenter. Vous devrez peut-être les gérer, mais vous ne le ferez probablement pas.

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
{ 
    // handle the event if you need to do something with the data. 
    // this is not over-riding the event, this is attaching a custom handler to the event 
    this.gotLeftButtonDown = false; 
    this.movedAfterMouseDown = false; 
} 

Cela ne surpasse pas l'événement. C'est un gestionnaire pour quand l'événement est soulevé! Les utilisateurs de votre contrôle écriront des gestionnaires comme celui-ci. Ne le réimplémentez pas. Ne le manipulez même pas à moins que vous ayez besoin de faire quelque chose avec les données. Ces événements sont écrits pour vous déjà.

Edit:

Alors que ma réponse était erronée en ce qu'elle n'a pas résolu le problème, il devrait encore être utile de comprendre pourquoi l'exception StackOverflow se passait.

protected virtual void OnMouseClick(MouseButtonEventArgs e) 
{ 
    base.RaiseEvent(e); 
    /* this will raise the OnMouseLeftButtonUp event if the MouseButtonEventArgs 
     designates that it came from the MouseLeftButtonUp event. 
     That will then call the OnMouseLeftButtonUp because e.RoutedEvent equals 
     MouseLeftButtonUpEvent. 

     The accepted answer does the following, to stop OnMouseLeftButtonUp being 
     called again, and the whole process repeating itself in an infinite loop. 

     args.RoutedEvent = MouseClickEvent; 
     base.RaiseEvent(e); // No longer fires MouseLeftButtonUp, breaking cycle. 

     // Changes the event to be fired, avoiding the cycle of 
     // OnMouseLeftButtonUp -> OnMouseClick -> OnMouseLeftButtonUp etc 
    */ 
} 

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
{ 
    base.OnMouseLeftButtonUp(e); 
    if (!this.movedAfterMouseDown) 
    { 
     OnMouseClick(e); // This will call OnMouseClick handler 
    } 
    this.gotLeftButtonDown = false; 
    this.movedAfterMouseDown = false; 
} 

Le flux de contrôle était:

  1. utilisateur génère MouseLeftButtonUpEvent
  2. OnMouseClick est appelé au sein de gestionnaire OnMouseLeftButtonUp
  3. OnMouseClick soulève événement MouseLeftButtonUp
  4. Aller à 2.

Le accepté des modifications de réponse à cette question:

  1. utilisateur génère MouseLeftButtonUpEvent
  2. OnMouseClick est appelé au sein de gestionnaire OnMouseLeftButtonUp
  3. OnMouseClick change l'événement routé à MouseClickEvent
  4. OnMouseClick soulève MouseClickEvent
  5. contrôle reprend

C'est ce que j'essayais d'expliquer dans les commentaires sur d'autres réponses. Si je n'étais pas assez clair, je m'en excuse. Je crois que serhio et moi n'étions pas synchronisés dans le fait que j'essayais d'expliquer la cause du stackvoverflow, alors qu'il cherchait une solution au code. Corrige moi si je me trompe.

+0

désolé de vous décevoir, mais il n'y a pas de MouseClick implémenté sur les contrôles utilisateur WPF. – serhio

+0

+1. @serhio: Quelle est la différence entre DoStuff et OnMouseClick? Rien! C'est ce qui se passe ici. –

+0

@Billy ONeal: Allez, pleople. J'appelle dans la méthode ** OnMouseClick ** qui N'EXISTE PAS dans la classe de base, le * différent * ** RaiseEvent ** mehtod qui EXISTE. Vous m'écrivez à peu près le même DoStuff – serhio