PresentationCore.dll中发生'System.StackOverflowException'

时间:2010-11-21 00:17:46

标签: .net wpf events wpf-controls

我有一个WPF UserControl,我尝试在其中实现自定义 MouseClick(因为 WPF(用户)控件上没有MouseClick事件)事件。

我得到了以下内容:

alt text

一些代码:

/// <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;
    }

那么,问题在哪里?

更新1

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

值不能为空。 参数名称:routedEvent

alt text

更新2

我成功实施的其他自定义事件(无问题) - SelectedChanged

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

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

更新3

System.Windows.Controls.Control的OnPreviewMouseDoubleClick实现:

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

更新5(对于坦克中的人)

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);
    }
}

3 个答案:

答案 0 :(得分:3)

您需要从自定义用户控件的所有部分中删除base.RaiseEvent(e)。这是堆栈溢出的原因。

如果您从UserControl继承,则已经为您实现了单击事件。你不需要重新实现。你可能需要处理它们,但很可能你不需要处理它们。

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;
}

这不会超越事件。这是事件被引发时的处理程序!您的控件的用户将像这样编写处理程序。不要重新实现它。除非您需要对数据执行某些操作,否则甚至不要处理它。这些事件已经为您编写。

编辑:

虽然我的答案是错误的,因为它没有解决问题,但理解为什么发生stackoverflow异常仍然有帮助。

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;
}

控制流程为:

  1. 用户生成MouseLeftButtonUpEvent
  2. 在OnMouseLeftButtonUp处理程序
  3. 中调用OnMouseClick
  4. OnMouseClick引发MouseLeftButtonUp事件
  5. 转到2。
  6. 接受的答案改为:

    1. 用户生成MouseLeftButtonUpEvent
    2. 在OnMouseLeftButtonUp处理程序
    3. 中调用OnMouseClick
    4. OnMouseClick将路由事件更改为MouseClickEvent
    5. OnMouseClick引发MouseClickEvent
    6. 控制恢复
    7. 这是我在其他答案的评论中试图解释的。如果我不够清楚,我为此道歉。我相信serhio和我不同步,我试图解释stackvoverflow的原因,当他正在寻找修复代码时。如果我错了,请纠正我。

答案 1 :(得分: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);
}

答案 2 :(得分:2)

我认为这是在这一行:

base.RaiseEvent(e);

如果您正在处理鼠标单击,则不希望再次引发该事件,因为这样只会再次调用您的处理程序,这将引发事件....