0
votes

All of my controls inherit from a base class that creates and assigns a OnAccept and OnCancel to the Enter and ESC keys.

private readonly Button _accept, _cancel;

public ViewUserControl()
{
    _accept = new Button();
    _cancel = new Button();

    _accept.Click += (o, e) => OnAccept();
    _cancel.Click += (o, e) => OnCancel();
}

// the base function depends on the child functions to implement a accept/cancel function, if it doesn't then those events will fire to the
// new button and not be used for anything
public virtual IButtonControl GetAcceptButton()
{
    return _accept;
}
public virtual IButtonControl GetCancelButton()
{
    return _cancel;
}

protected virtual void OnAccept() { }
protected virtual void OnCancel()
{
    this.ClosingEvent();
}

However, when the user is in a multiline textbox, the enter key is kicking off the OnAccept of the form rather than putting a new line into the textbox (which is the expected behaviour).

Currently, to get around this, i have to find the focused control of the form and if it's a textbox, then manually put the newline in. However when I do this, the cursor resets to the start of the textbox.

protected override void OnAccept()
{
    var focused = FindFocusedControl(this);
    if (focused is TextBox)
    {
        focused.Text += Environment.NewLine;
    }
    else
    {
        base.OnAccept();
    }
}

public static Control FindFocusedControl(Control control)
{
    var container = control as ContainerControl;
    while (container != null)
    {
        control = container.ActiveControl;
        container = control as ContainerControl;
    }
    return control;
}

My questions are:

Is there a way to bypass the OnAccept event so the enter event is recognised by the textbox?

Is there a way to call the textbox's enter event manually?

How do I set the cursor to the end of the textbox after I manually put in a line break?

An answer to any of these questions will achieve the result that I'm after, ordered in preference of solution.

UPDATE:

I did find a way to move the caret (not cursor as I called it in the original question) to the end using RichTextBox.SelectionStart however, I'd prefer a more elegant solution.

UPDATE 2:

For anyone else with the same problem, this is what I now do:

From the child control:

txtDetails.GotFocus += (o,e) => AcceptButtonStatus(false);
txtDetails.LostFocus += (o, e) => AcceptButtonStatus(true);

From the base control:

protected void AcceptButtonStatus(bool enabled)
{
    this.ParentForm.AcceptButton = enabled?_accept:null;
}

So whenever the textbox gets focus, I remove the accept button from the form.

1

1 Answers

1
votes

Here is a post on how to externally call component events.

How can I programmatically generate keypress events in C#?

As for the Accept event, your dialog is intercepting that before the control ever sees it. The only thing that might work would be to add a form event that watches focus changes and if the focus is a multiline text control, you set the AcceptButton control for the form to null (assuming you are using AcceptButton and CancelButton to generate the Accept/Cancel events).