How to override the preferred size of a WinForms TextBox?

巧了我就是萌 提交于 2019-12-01 06:38:52

问题


A TextBox in .NET does not let you adjust its height (there isn't even an AutoSize option).

i have a textbox that is cutting off the bottom of text in the box:

Example 1:

Example 2:

What i need is to fix the PreferredSize calculation; to override the bug in .NET WinForms TextBox control.

i created a descendant FixedTextBox, and tried overriding the protected GetPreferredSize:

public override Size GetPreferredSize(Size proposedSize)
{
   Size size = base.GetPreferredSize(proposedSize);

   if (this.BorderStyle == BorderStyle.None)
   {
      size.Height += 2;
   }

   return size;
}

My overridden method is being called, but the TextBox isn't altering it's "preferred" size.

i also tried overriding the protected DefaultSize property:

protected override Size DefaultSize 
{
   get 
   { 
      Size size = base.DefaultSize;

      if (this.BorderStyle == BorderStyle.None)
      {
         size.Height += 2;
      }

      return size;
   }
}

And it is called during construction, but is never called again when the "default size" is different (e.g. after i change the BorderStyle), and doesn't affect the size of the TextBox.

What is the proper way to hook into the .NET WinForms "AutoSize" infrastructure, to adjust the "preferred" size?

Note: Just because i overrode GetPreferredSize doesn't mean the solution involves overriding GetPreferredSize

tl;dr: Someone step into textBox1.Height += 1 and figure why it does nothing.

Related (but different) questions

  • Changing WinForms TextBox to BorderStyle.None causes text to be cut off

    Mentions the problem, accepting solutions; contrast with this question which asks how to use the "preferred size" infrastructure in WinForms

  • How to make TextBox rethink it's preferred height?

    Mentions the problem, looking for solutions involving having the TextBox recalculate its preferred height; contrast to this question which accepts that the textbox cannot recalculate its preferred height, and even if it could it wouldn't help because the auto-size calculation is wrong


回答1:


See the answer of Phil Wright for the SO question What is the purpose of Control.GetPreferredSize method?:

"The Control.GetPreferredSize is called by containers as part of the layout cycle.

It allows the called control to return the size they would like to have if possible. The container does not have to honor this requested size however. For example, when a control has a Dock setting of Top the width would be defined as the width of the containing control regardless of the value returned from the GetPreferredSize method. This method is particularly useful for containers like the flow layout control which will position each child control one after another." [Phil Wright]

This means that this PreferredSize will not change the size of your TextBox.


I think this solves your problem:

public class MyTextBox : TextBox
{
    const int RequestedHight = 30;

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        AssureRequestedHight();
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        AssureRequestedHight();
    }

    private void AssureRequestedHight()
    {
        if (this.Size.Height != RequestedHight && !this.Multiline) {
            this.Multiline = true;
            this.MinimumSize = new Size(0, RequestedHight);
            this.Size = new Size(this.Size.Width, RequestedHight);
            this.Multiline = false;
        }
    }
}



回答2:


Have you tried doing an override of

protected override System.Drawing.Size DefaultSize
{ get { return new System.Drawing.Size( 145, 52 ); } }

or whatever size you need

Depending on your purposes, and something I've done in the past was to create my own sub-classes for certain controls and did an override of things like FontSize, FontName, Size, etc and made them all as read-only (only applying an externally visible "getter" ). By doing this, any instances of my class that were put onto a WinForms form that had the design-time serialization would nag at me to get rid of the "read-only" property from the designer. After doing so early on in the development, these controls never had a problem again. If I ever changed it, the form would get the newest value/size/font in the designer without having to go through every form and every instance of the control.

I found it to work well with things like a textbox that would be showing date only, or date/time fields, additionally applied to labels, command buttons, and other "common" purpose elmeents. So, throughout the app, it was almost like applying a cascading style sheet, but at a WinForms level.

Just a thought and hope it opens you to another approach to your dilemma.




回答3:


I found a solution for the Rich text box height issues.. i have modified it a for general use..

Create following structs in your application....

[StructLayout(LayoutKind.Sequential)]
    public struct RECT {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SCROLLBARINFO {
        public Int32 cbSize;
        public RECT rcScrollBar;
        public Int32 dxyLineButton;
        public Int32 xyThumbTop;
        public Int32 xyThumbBottom;
        public Int32 reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public Int32[] rgstate;
    }

Create following private variables in your class for form (where ever you need to calculate rich text height)

private UInt32 SB_VERT = 1;
        private UInt32 OBJID_VSCROLL = 0xFFFFFFFB;

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollRange(IntPtr hWnd, UInt32 nBar, out Int32 lpMinPos, out Int32 lpMaxPos);

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollBarInfo(IntPtr hWnd, UInt32 idObject, ref SCROLLBARINFO psbi);

Add following method to your Class for form

private int CalculateRichTextHeight(string richText) {
            int height = 0;
            RichTextBox richTextBox = new RichTextBox();
            richTextBox.Rtf = richText;
            richTextBox.Height = this.Bounds.Height;
            richTextBox.Width = this.Bounds.Width;
            richTextBox.WordWrap = false;
            int nHeight = 0;
            int nMin = 0, nMax = 0;

            SCROLLBARINFO psbi = new SCROLLBARINFO();
            psbi.cbSize = Marshal.SizeOf(psbi);

            richTextBox.Height = 10;
            richTextBox.ScrollBars = RichTextBoxScrollBars.Vertical;

            int nResult = GetScrollBarInfo(richTextBox.Handle, OBJID_VSCROLL, ref psbi);
            if (psbi.rgstate[0] == 0) {
                GetScrollRange(richTextBox.Handle, SB_VERT, out nMin, out nMax);
                height = (nMax - nMin);
            }

            return height;
        }

You may need to modify above method to make it work as per your requirement... Make sure to send Rtf string as parameter to method not normal text and also make sure to assign available width and height to the Richtextbox variable in the method...

You can play with WordWrap depending on your requirement...



来源:https://stackoverflow.com/questions/8493843/how-to-override-the-preferred-size-of-a-winforms-textbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!