问题
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 overridingGetPreferredSize
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