Limit the number of lines entered in a WPF text field

I am trying to limit the number of lines that a user can enter in a text box.

I study - the closest I can find is: Limit the maximum number of characters per line in the text box .

And Limit the maximum number of characters per line in the text box that appears for winforms.

This is not exactly what I need ... it is also worth mentioning that there is a false property maxlines , which I found only the restrictions that appear in the text box.

My requirements:

  • No monolayer font required
  • Limit the text box to a maximum of 5 lines
  • accepts carriage return
  • Do not allow additional carriage returns
  • Stops text input when reaching maximum length
  • Wraps around a text (not really caring if it does it between words or breaks whole words)
  • It processes the text that is inserted into the control and will only insert what is suitable.
  • No scrollbars
  • Also - and that would be nice - having the ability to limit the number of characters per line

These requirements are designed to create a WYSIWYG text field that will be used to collect data that will ultimately be printed, and the fonts must be changed — if the text is cropped or too large for a fixed-size string, then it will print this way (even if it does not look right).

, , , . .

XAML

 <TextBox TextWrapping="Wrap" AcceptsReturn="True"
        PreviewTextInput="UIElement_OnPreviewTextInput"
        TextChanged="TextBoxBase_OnTextChanged" />

 public int TextBoxMaxAllowedLines { get; set; }
    public int TextBoxMaxAllowedCharactersPerLine { get; set; }


    public MainWindow()
    {
        InitializeComponent();

        TextBoxMaxAllowedLines = 5;
        TextBoxMaxAllowedCharactersPerLine = 50;
    }

    private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox textBox = (TextBox)sender;

        int textLineCount = textBox.LineCount;

        if (textLineCount > TextBoxMaxAllowedLines)
        {
            StringBuilder text = new StringBuilder();
            for (int i = 0; i < TextBoxMaxAllowedLines; i++)
                text.Append(textBox.GetLineText(i));

            textBox.Text = text.ToString();
        }

    }

    private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        TextBox textBox = (TextBox)sender;

        int textLineCount = textBox.LineCount;


        for (int i = 0; i < textLineCount; i++)
        {
            var line = textBox.GetLineText(i);

            if (i == TextBoxMaxAllowedLines-1)
            {
                int selectStart = textBox.SelectionStart;
                textBox.Text = textBox.Text.TrimEnd('\r', '\n');
                textBox.SelectionStart = selectStart;

                //Last line
                if (line.Length > TextBoxMaxAllowedCharactersPerLine)
                    e.Handled = true;
            }
            else
            {
                if (line.Length > TextBoxMaxAllowedCharactersPerLine-1 && !line.EndsWith("\r\n"))
                    e.Handled = true;    
            }

        }
    }

- , .

, , ... , , , - : qaru.site/questions/109195/...

, . , , - .

+4
6

- , - ...

- , , .

textChanged - pasing - ( key_preview ), ' m, .

XAML

<TextBox TextWrapping="Wrap" AcceptsReturn="True" 
             HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled">
       <i:Interaction.Behaviors>
            <lineLimitingTextBoxWpfTest:LineLimitingBehavior TextBoxMaxAllowedLines="5" />

        </i:Interaction.Behaviors>
    </TextBox>

( )

/// <summary> limits the number of lines the textbox will accept </summary>
public class LineLimitingBehavior : Behavior<TextBox>
{
    /// <summary> The maximum number of lines the textbox will allow </summary>
    public int? TextBoxMaxAllowedLines { get; set; }

    /// <summary>
    /// Called after the behavior is attached to an AssociatedObject.
    /// </summary>
    /// <remarks>
    /// Override this to hook up functionality to the AssociatedObject.
    /// </remarks>
    protected override void OnAttached()
    {
        if (TextBoxMaxAllowedLines != null && TextBoxMaxAllowedLines > 0)
            AssociatedObject.TextChanged += OnTextBoxTextChanged;
    }

    /// <summary>
    /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
    /// </summary>
    /// <remarks>
    /// Override this to unhook functionality from the AssociatedObject.
    /// </remarks>
    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= OnTextBoxTextChanged;
    }

    private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox textBox = (TextBox)sender;

        int textLineCount = textBox.LineCount;

        //Use Dispatcher to undo - http://stackoverflow.com/a/25453051/685341
        if (textLineCount > TextBoxMaxAllowedLines.Value)
            Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action) (() => textBox.Undo()));
    }
}

System.Windows.InterActivity XAML:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+4

, , , , . , , GUI Codebehind . , , , WPF.

: - , ?

: DependencyProperty, CoerceCallback // .

, - ( ) - : DataContext = "{Binding RelativeSource = {RelativeSource self}}" UserControl XAML.

XAML

<TextBox TextWrapping="Wrap"
     Text="{Binding NotesText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
     AcceptsReturn="True"
     HorizontalScrollBarVisibility="Disabled"
     VerticalScrollBarVisibility="Disabled">

Codebehind (#)

    const int MaxLineCount = 10;
    const int MaxLineLength = 200;

    public static readonly DependencyProperty NotesTextProperty =
            DependencyProperty.Register(
                name: "NotesText",
                propertyType: typeof( String ),
                ownerType: typeof( SampleTextBoxEntryWindow ),
                typeMetadata: new PropertyMetadata(
                    defaultValue: string.Empty,
                    propertyChangedCallback: OnNotesTextPropertyChanged,
                    coerceValueCallback: CoerceTextLineLimiter ) );

    public string NotesText
    {
        get { return (String)GetValue( NotesTextProperty ); }
        set { SetValue( NotesTextProperty, value ); }
    }

    private static void OnNotesTextPropertyChanged(DependencyObject source,
        DependencyPropertyChangedEventArgs e)
    {
        // Whatever you want to do when the text changes, like 
        // set flags to allow buttons to light up, etc.
    }

    private static object CoerceTextLineLimiter(DependencyObject d, object value)
    {
        string result = null;

        if (value != null)
        {
            string text = ((string)value);
            string[] lines = text.Split( '\n' );

            if (lines.Length <= MaxLineCount)
                result = text;
            else
            {
                StringBuilder obj = new StringBuilder();
                for (int index = 0; index < MaxLineCount; index++)
                    if (lines[index].Length > 0)
                        obj.AppendLine( lines[index] > MaxLineLength ? lines[index].Substring(0, MaxLineLength) : lines[index] );

                result = obj.ToString();
            }
        }
        return result;
    }

( , ).

, , , - , ( Regx) :

private static object CoercePhoneNumber(DependencyObject d, object value)
    {
        StringBuilder result = new StringBuilder();

        if (value != null)
        {
            string text = ((string)value).ToUpper();

            foreach (char chr in text)
                if ((chr >= '0' && chr <= '9') || (chr == ' ') || (chr == '-') || (chr == '(') || (chr == ')'))
                    result.Append( chr );

        }
        return result.ToString();
    }

, , . Coerce , - .

0

, MaxLines TextBox, , , .

My_Defined_MaxTextLength MaxLenght

My_MaxLines -

My_TextBox.TextChanged += (sender, e) =>
                 {
                     if(My_TextBox.LineCount > My_MaxLines)
                     {
                         My_TextBox.MaxLength = My_TextBox.Text.Length;
                     }
                     else
                     {
                         My_TextBox.MaxLength = My_Defined_MaxTextLength;
                     }

                 };

0

. .

public class LineLimitingBehavior : Behavior<TextBox>
{
    public int? TextBoxMaxAllowedLines { get; set; }

    protected override void OnAttached()
    {
        if (TextBoxMaxAllowedLines == null || !(TextBoxMaxAllowedLines > 0)) return;

        AssociatedObject.PreviewTextInput += OnTextBoxPreviewTextInput;
        AssociatedObject.TextChanged += OnTextBoxTextChanged;
    }

    private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
    {
        var textBox = (TextBox)sender;

        if (textBox.LineCount > TextBoxMaxAllowedLines.Value)
            Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)(() => textBox.Undo()));
    }

    private void OnTextBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox)sender;
        var currentText = textBox.Text;
        textBox.Text += e.Text;

        if (textBox.LineCount > TextBoxMaxAllowedLines.Value)
            e.Handled = true;

        textBox.Text = currentText;
        textBox.CaretIndex = textBox.Text.Length;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewTextInput -= OnTextBoxPreviewTextInput;
        AssociatedObject.TextChanged -= OnTextBoxTextChanged;
    }
}
0

, :

XAML

<TextBox TextWrapping="Wrap" AcceptsReturn="True"
    PreviewTextInput="UIElement_OnPreviewTextInput"
    TextChanged="TextBoxBase_OnTextChanged" />

const int MaxLineCount = 10;

private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = (TextBox)sender;

    int textLineCount = textBox.LineCount;

    if (textLineCount > MaxLineCount)
    {
        StringBuilder text = new StringBuilder();
        for (int i = 0; i < MaxLineCount; i++)
        {
            text.Append(textBox.GetLineText((textLineCount - MaxLineCount) + i - 1));
        }
        textBox.Text = text.ToString();
    }
}
0
string prev_text = string.Empty;
    private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
    {
        int MaxLineCount = 5;
        if (textBox1.LineCount > MaxLineCount)
        {
            int index = textBox1.CaretIndex;
            textBox1.Text = prev_text;
            textBox1.CaretIndex = index;
        }
        else
        {
            prev_text = textBox1.Text;
        }
    }
0

Source: https://habr.com/ru/post/1611779/


All Articles