I have a .NET UWP TextBox with a good deal of text, and I want to search for a word in it. When I click on the button to start my search, it will find the first occurrence of this word. When I click again, it will find the second, like ctrl+f in Notepad).
I want to get focus on the found world, but when is text is long enough that there is a scrollbar in, it will not bring the found word into view.
This is a screengrab of the screen in this state, showing how I must resize the window to see the found word.
Here is my code for searching (textarea
is of type TextBox):
private void Find(string text)
{
textarea.Focus(FocusState.Programmatic);
var start = textarea.SelectionStart + textarea.SelectionLength;
var found = (bool)checkboxFindCaseSensitive.IsChecked ? textarea.Text.IndexOf(text, start) : textarea.Text.IndexOf(text, start, StringComparison.CurrentCultureIgnoreCase);
if (found == -1)
{
textarea.SelectionStart = 0;
found = (bool)checkboxFindCaseSensitive.IsChecked ? textarea.Text.IndexOf(text, start) : textarea.Text.IndexOf(text, start, StringComparison.CurrentCultureIgnoreCase);
if (found == -1) return;
}
textarea.SelectionStart = found;
textarea.SelectionLength = text.Length;
}
I have already tried to put textarea.Focus(FocusState.Programmatic);
at the end of method as well as textarea.Focus(FocusState.Pointer);
, but neither helped.
UPDATE:
I've found that it's focusing correctly, but to the last found word (to position, where is the cursor before find next word), not to the currently found word.
So I need to update focus to current SelectionStart
, not to the last. Any ideas? I have already tried to change SelectionStart
again, replace text and update layout - nothing helps.
What you can do is to measure the height of your text until the index, and resize the textbox accordingly.
private static float GetTextHeightUntilIndex(TextBox textBox, int index)
{
var height = 0;
var textBuffer = textBox.Text;
// Remove everything after `index` in order to measure its size
textBox.Text = textBuffer.Substring(0, index);
textBox.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
var height = textBox.DesiredSize().Height;
// Put the full text back
textBox.Text = textBuffer;
return height;
}
private void Find(string text)
{
textarea.Focus(FocusState.Programmatic);
var start = textarea.SelectionStart + textarea.SelectionLength;
var found = (bool)checkboxFindCaseSensitive.IsChecked ? textarea.Text.IndexOf(text, start) : textarea.Text.IndexOf(text, start, StringComparison.CurrentCultureIgnoreCase);
if (found == -1)
{
textarea.SelectionStart = 0;
found = (bool)checkboxFindCaseSensitive.IsChecked ? textarea.Text.IndexOf(text, start) : textarea.Text.IndexOf(text, start, StringComparison.CurrentCultureIgnoreCase);
if (found == -1) return;
}
textarea.SelectionStart = found;
textarea.SelectionLength = text.Length;
// -------------------
var cursorPosInPx = GetTextHeightUntilIndex(textarea, found);
// First method: resize your textbox to the selected word
textarea.Height = cursorPosInPx;
// Second method: scroll the textbox
var grid = (Grid)VisualTreeHelper.GetChild(textarea, 0);
for (var i = 0; i <= VisualTreeHelper.GetChildrenCount(grid) - 1; i++)
{
object obj = VisualTreeHelper.GetChild(grid, i);
if (obj is ScrollViewer)
((ScrollViewer)obj).ChangeView(null, cursorPosInPx, null, true);
}
}
Be careful however, for the first method, depending on whatlayout your textbox is, resizing the control may have an unwanted effect or no effect at all.