How to restrict the input in TextBox only until the edge of the box?

Sarah 186 Reputation points
2022-02-21T11:15:01.15+00:00

I want to restrict the input in the TextBox only to the edge of the box? I tried it with MaxLength property but I didn't get the result I wanted. Are there other options?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,768 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Castorix31 85,116 Reputation points
    2022-03-08T22:20:22.087+00:00

    From comments, a test by comparing text lenght with TextBox client width (I tested with renderScope.ActualWidth (Reflection) which seems accurate) =>

         <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="27" Margin="79,133,0,0" VerticalAlignment="Top" Width="225" PreviewKeyDown="textBox1_PreviewKeyDown"/>
    

    Main code :

        public MainWindow()
        {
            InitializeComponent();
            DataObject.AddPastingHandler(textBox1, OnPaste);
        }
    
        private KeyConverter kc = new KeyConverter();
    
        private void textBox1_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string sText = tb.Text;
            string sKey = kc.ConvertToString(e.Key);
            bool bCapsLock = Keyboard.IsKeyToggled(Key.CapsLock);
            bool bShift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
            bool bCharacter = false;
            if ((!bCapsLock && !bShift) || (bCapsLock && bShift))
            {
                sKey = sKey.ToLower();
            }
            if (sKey != null && sKey.Length == 1)
            {
                if (char.IsLetterOrDigit(sKey[0]))
                {
                    sText += sKey[0];
                    bCharacter = true;
                }
            }
            // System.Windows.Controls.TextBoxView
            var renderScope = tb.GetFieldValue<FrameworkElement>("_renderScope") as IServiceProvider;
            var nActualWidthView = (double)renderScope.InvokeMethod("get_ActualWidth");
            var sz = MeasureText(tb, sText);
            if (bCharacter && sz.Width >= nActualWidthView)
            {
                e.Handled = true;
                Console.Beep(1000, 10);
            }
        }        
    
        private void OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            e.Handled = true;
            e.CancelCommand();
        }
    
        // Adapted from MSAGL
        public Size MeasureText(TextBox ctrl, string text)
        {
            FormattedText formattedText = new FormattedText(
                text,
                System.Globalization.CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface(ctrl.FontFamily, ctrl.FontStyle, ctrl.FontWeight, ctrl.FontStretch),
                ctrl.FontSize,
                new SolidColorBrush(Colors.Black),
                VisualTreeHelper.GetDpi(this).PixelsPerDip);
            return new Size(formattedText.Width, formattedText.Height);
        }   
    

    Utility class for Reflection :

    // https://sudonull.com/post/12432-Bug-when-working-TextBoxGetLineText-in-NET-WPF
    public static class ReflectionExtensions
    {
        public static T GetFieldValue<T>(this object obj, string name)
        {
            var bindingFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
            var field = obj.GetType().GetField(name, bindingFlags);
            if (field == null)
                field = obj.GetType().BaseType.GetField(name, bindingFlags);
            return (T)field?.GetValue(obj);
        }
        public static object InvokeMethod(this object obj, string methodName, params object[] methodParams)
        {
            var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
            var bindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static;
            System.Reflection.MethodInfo method = null;
            var type = obj.GetType();
            while (method == null && type != null)
            {
                method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
                var intfs = type.GetInterfaces();
                if (method != null)
                    break;
                foreach (var intf in intfs)
                {
                    method = intf.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
                    if (method != null)
                        break;
                }
                type = type.BaseType;
            }
            return method?.Invoke(obj, methodParams);
        }
    }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.