Text wrapping adds a new dimension to restricting the number of lines in a TextBox, to do so we need be aware that the number of lines can be affected by the resolution and zooming factor applied at the operating system level, but also many layout concepts utilised in UWP layout are generally relative or dynamic and affect the visual state is ways that are hard to keep consistent for all users.
For instance, text that just fits on two lines in one user's runtime, might easily wrap into 3 lines for another user or when the width of the form is changed.
Even after doing your best to limit a wrapped text box to a specific number of lines, we have to expect that over time, we will get it wrong, if the number of lines is important for layout reasons then you might consider trimming or truncating the text or even using RichTextBlockOverflow
You can try this solution from How can I measure the Text Size in UWP Apps?, and then validate against the height of the text, not specifically the number of lines.
However I have in the past also found success by setting the TextBox to a fixed height (and of course width) and validated against the Scrollbar state. Unfortunately it is hard to access the vertical scrollbar visibility directly, but we can use the ExtentHeight
and the ViewportHeight
on the ScrollViewer
element that is inside the TextBox
template.
If the ExtentHeight
is greater than the ViewportHeight
then the scrollbar should be visible. If the Visual layout only allows the total number of lines that you want to support then the scrollbar should not ever be visible.
Accessing the ScrollViewer
gets interesting, options are discussed here How do access the scrollviewer of a TextBox in code
So try this as an adaptation to the solution from @10 Develops:
private void textBox_TextChanged(object sender, RoutedEventArgs e)
{
var scroller = (sender as TextBox).FindChild<ScrollViewer>();
if (scroller.ExtentHeight > scroller.ViewportHeight)
{
Debug.WriteLine("Limit reached");
//your code here
}
}
With this extension method defined in a static class:
(using pattern matching, so a bit different to the original referenced post)
public static T FindChild<T>(this DependencyObject parent) where T : UIElement
{
if (parent is T matchedParent) return matchedParent;
int children = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < children; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T matchedChild)
return matchedChild;
else
{
T tChild = FindChild<T>(child);
if (tChild != null) return tChild;
}
}
return null;
}
I don't normally use this for validation of content, but I do use it to add buttons to toolbars that allow the user to quickly scroll to the top or bottom of the content and to toggle the visibility of such controls.