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.