“System.StackOverflowException”发生在PresentationCore.dll中

发布于 2024-10-03 17:45:20 字数 2235 浏览 0 评论 0原文

我有一个 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;
    }

那么,问题出在哪里?

UPDATE 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

UPDATE 2

我成功实现的另一个自定义事件(工作没有问题) - SelectedChanged< /code>:

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

I have a WPF UserControl in which I try to implement the custom MouseClick (because there is no MouseClick event on a WPF (User)Control) event.

I got the following:

alt text

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

So, where is the problem?

UPDATE 1

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

Value cannot be null.
Parameter name: routedEvent

alt text

UPDATE 2

An other custom event I implemented successfully (work without problems) - SelectedChanged:

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

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

UPDATE 3

System.Windows.Controls.Control's OnPreviewMouseDoubleClick implementation:

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

Update 5 (for people in the tank)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

人事已非 2024-10-10 17:45:21

我认为是这样的:

base.RaiseEvent(e);

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

I think it's in this line:

base.RaiseEvent(e);

If you are handling the mouse click you don't want to raise the event again as that will simply call your handler again, which will raise the event....

阳光的暖冬 2024-10-10 17:45:21
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);
}
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);
}
初见终念 2024-10-10 17:45:20

您需要从自定义用户控件的所有部分中删除 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. OnMouseClick 在 OnMouseLeftButtonUp 处理程序中调用
  3. OnMouseClick 引发 MouseLeftButtonUp 事件
  4. Goto 2。

接受的答案更改为:

  1. 用户生成 MouseLeftButtonUpEvent
  2. OnMouseClick 在 OnMouseLeftButtonUp 处理程序中调用
  3. OnMouseClick 将路由事件更改为 MouseClickEvent
  4. OnMouseClick 引发 MouseClickEvent
  5. Control resumes

This这就是我试图在其他答案的评论中解释的内容。如果我说得不够清楚,我对此表示歉意。我相信 serhio 和我不同步,因为当他在寻找代码修复时,我试图解释 stackvoverflow 的原因。如果我错了请纠正我。

You need to remove the base.RaiseEvent(e) from ALL parts of your custom user control. That is the cause of the stack overflow.

If you're inheriting from UserControl, the click events are already implemented for you. You do NOT need to re-implement. You MAY need to handle them though, but most probably you do not.

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

This does not over-ride the event. This is a handler for when the event is raised! Users of your control will write handlers just like this one. Don't reimplement it. Don't even handle it unless you need to do something with the data. These events are written for you already.

Edit:

While my answer was wrong in that it didn't fix the issue, it should still be helpful to understand WHY the stackoverflow exception was happening.

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

The control flow was:

  1. User generates MouseLeftButtonUpEvent
  2. OnMouseClick is called within OnMouseLeftButtonUp handler
  3. OnMouseClick raises MouseLeftButtonUp event
  4. Goto 2.

The accepted answer changes to this:

  1. User generates MouseLeftButtonUpEvent
  2. OnMouseClick is called within OnMouseLeftButtonUp handler
  3. OnMouseClick changes the routed event to MouseClickEvent
  4. OnMouseClick raises MouseClickEvent
  5. Control resumes

This is what I was trying to explain in comments on other answers. If I wasn't clear enough I apologise for that. I believe that serhio and I were out of sync in that I was trying to explain the cause of the stackvoverflow, when he was looking for a fix to the code. Correct me if I'm wrong.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文