This is a weird one and I don't really even know what to search for, but trust me I have.
I have a text box and bound to its OnTextChanged
event is the below method.
The purpose here is to give the text box focus, move the cursor to the end of the TextBox and return focus back to whatever was actually focused (usually a button). The problem is that it seems the TextBox is not "redrawn" (for lack of a better word?) before I send the focus back to the originally focused element so the cursor position does not update on screen (though all properties think it has).
Currently, I have brutally hacked this together that basically delays the refocus of the previous focused item by 10 ms and runs it in a different thread so the UI has time to update. Now, this is obviously an arbitrary amount of time and works fine on my machine but someone running this app on an older machine may have problems.
Is there a proper way to do this? I can't figure it out.
private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
if (sender == null) return;
var box = sender as TextBox;
if (!box.IsFocused)
{
var oldFocus = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
box.Select(box.Text.Length, 0);
Keyboard.Focus(box); // or box.Focus(); both have the same results
var thread = new Thread(new ThreadStart(delegate
{
Thread.Sleep(10);
Dispatcher.Invoke(new Action(() => oldFocus.Focus()));
}));
thread.Start();
}
}
EDIT
A new idea I had was to run the oldFocus.Focus() method once the UI is done updating so I tried the following but I get the same result :(
var oldFocus = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
Dispatcher.Invoke(DispatcherPriority.Send, new Action(delegate
{
box.Select(box.Text.Length, 0);
box.Focus();
}));
Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => oldFocus.Focus()));