从父控件中触发用户控件事件

3

我有一个用户控件,其中包含以下重写事件:

protected override void OnKeyDown(KeyEventArgs e)
{
    if (e.KeyCode == Keys.Left )
        DoSomething();
}

当我将用户控件放在我的主窗体上时,此事件未被触发。如何从父窗体访问此事件?
protected override void OnKeyDown(KeyEventArgs e)
{
    e.Handled = true;
    if (e.KeyCode == Keys.Left)
        Move(pt.X,pt.Y);//Move is a function within the usercontrol
    else if (e.KeyCode == Keys.Right)
        Move(pt.X,pt.Y);
   //other conditions
   e.Handled = false;
}

我需要通知父级元素该事件。

你确定在按键时用户控件有键盘焦点吗?我不明白为什么它不会被触发。我也不清楚你是否试图将事件冒泡到主窗体。 - Rotem
Rotem,用户控件是一个Windows表单,在转换为用户控件后工作得非常完美。现在我把它转换成了用户控件,并希望能够从父窗体触发操作。我在另一个项目中也遇到了同样的问题,当我建立一个计算器并将其转换为用户控件时,现在我把它放入了Windows表单中,但按钮没有响应。 - Avrum
听起来解决方案应该是在用户控件上创建一个公共方法,该方法调用onKeyDown方法,但你提到你尝试过这种方法,但它没有起作用。在哪个部分它没有起作用? - Rotem
我已将此建议发布为答案。如果这不是您想要实现的,请澄清一下。 - Rotem
你好,我已经发布了一个更新的答案,我相信这就是你要找的。但请注意,由于问题不是特别清晰,你会得到一些冲突的答案。我认为这不是一个难解决的问题,但在未来,请尽量清楚地说明你想要实现什么。这样你会得到更好的回应!最好的问候。 - Dr. Andrew Burnett-Thompson
没错,我们已经回答了三个不同的问题 :) - Rotem
2个回答

2
如果我理解正确,您正在尝试从父窗体中调用用户控件的OnKeyDown方法。
这是主窗体类:
public class Form1 : Form
{
    private UserControl1 myControl;

    public Form1()
    {
        myControl = new UserControl1();
        Controls.Add(myControl);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        myControl.InvokeOnKeyDown(e);
    }
}

这是用户控件:

public class UserControl1 : UserControl
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        MessageBox.Show("Key Down Fired!");
    }

    public void InvokeOnKeyDown(KeyEventArgs e)
    {
        OnKeyDown(e);
    }
}

关于箭头键的编辑: 箭头键通常不被视为输入键,因此不会传递到键方法中。要更改此设置,您必须重写 IsInputKey 方法,如下所示:

 protected override bool IsInputKey(Keys e)
 {
     if (e == Keys.Up || e == Keys.Down ||
         e == Keys.Left || e == Keys.Right) return true;
     return base.IsInputKey(e);
 }

Rotem,我尝试了你的解决方案,但没有成功。不过我进行了调试并发现它适用于不同的键,除了箭头键。我搜索了一些解决方案,但没有找到任何有用的信息。你有什么想法吗? - Avrum

1

根据您更新的问题和代码示例,如果您希望父窗体被通知到移动操作的发生,您需要在用户控件中创建一个事件,并在父窗体中订阅它。可以通过以下示例实现该目的。如果这解决了您的问题,请告诉我,否则请提供更多详细信息。

祝好

// Define custom EventArgs to pass into the Move event
public class MoveEventArgs : EventArgs
{
    private Point _movePoint;
    public MoveEventArgs(Point movePoint)
    {
        _movePoint = _movePoint;
    }

    public Point MovePoint { get { return _movePoint; } } 
}

// Define a custom user control that raises an event to subscribers on move
public class MyUserControl : UserControl
{
    public event EventHandler<MoveEventArgs> Moved;

    protected override void OnKeyDown(KeyEventArgs e)
    {
        e.Handled = true;
        if (e.KeyCode == Keys.Left)
        {
            Move(pt.X,pt.Y);//Move is a function within the usercontrol
            OnMoved(pt);
        }   
        else if (e.KeyCode == Keys.Right)
        {
            Move(pt.X,pt.Y);
            OnMoved(pt);
        }
       //other conditions
       e.Handled = false;
    }

    // Raises a custom event, Moved 
    protected void OnMoved(Point movePoint)
    {
        var handler = Moved;
        if (handler != null)
        {
            handler(this, new MoveEventArgs(movePoint);
        }
    }
}

// How to subscribe to the event (and be notified of move)
public class MyParentForm : Form
{
    public MyParentForm()
    {
        InitializeComponent();
        _myUserControl.Moved += new EventHandler<MoveEventArgs>(MyUserControl_Moved);
    }

    private void MyUserControl_Moved(object sender, MoveEventArgs e)
    {
        // e.MovePoint now contains the point that the usercontrol was moved to
        // this event will fire whenever the user presses Left or Right arrow
    }
}

谢谢,我会编辑我的评论。所以,您希望在父窗体中通知用户控件的OnKeyDown事件?您尝试过挂钩到该事件吗?例如:UserControl.KeyDown += new EventHandler<EventArgs>(myForm.KeyDownOfUserControl) - Dr. Andrew Burnett-Thompson
安德鲁,虽然如此,我仍需要保持用户控件的功能。我需要能够在其他应用程序中使用带有onkeyDown事件的用户控件,并且不会在每个应用程序中重复按键操作。 - Avrum
@Dr.AndrewBurnett-Thompson:感谢您指引我正确的方向。我在我的自定义控件中使用了您的方式以电梯式的方式触发事件(它是一个带有分层数据模板的树形视图,我需要将选定的事件从子级传递到根级,然后传递到我的窗口)。我想知道是否还有其他更加优雅的方式? - Hoàng Long
1
@HoàngLong 是的,请查找EventAggregator模式。特别是有第三方实现,例如Unity(Prism)中的一个。在核心上,它只是一个消息代理。通过依赖注入注入到ViewModels中,或者在视图代码后台静态访问,您可以在应用程序中的任何地方发布/订阅而不需要耦合(用户控件不需要知道彼此)。 - Dr. Andrew Burnett-Thompson
@Dr.AndrewBurnett-Thompson:非常感谢!希望您周末愉快 :) - Hoàng Long
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接