英文:
How to remove border of top and both sides of a TextBox
问题
我遇到了如何移除 Windows Forms 项目中 TextBox 顶部和两侧边框的问题。
我希望 TextBox 看起来像这样:
我的文本框代码:
this.textBox1.Anchor = System.Windows.Forms.AnchorStyles.None;
this.textBox1.Location = new System.Drawing.Point(85, 101);
this.textBox1.Name = "textBox1";
this.textBox1.PlaceholderText = "Login";
this.textBox1.Size = new System.Drawing.Size(213, 23);
this.textBox1.TabIndex = 0;
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
你能帮我解决这个问题吗?
英文:
I'm with struggle with how to remove border of top and both sides of TextBox in Windows Forms project
I want the TextBox looks like this:
My textbox code:
this.textBox1.Anchor = System.Windows.Forms.AnchorStyles.None;
this.textBox1.Location = new System.Drawing.Point(85, 101);
this.textBox1.Name = "textBox1";
this.textBox1.PlaceholderText = "Login";
this.textBox1.Size = new System.Drawing.Size(213, 23);
this.textBox1.TabIndex = 0;
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
Could you help me with this?
答案1
得分: 3
首先,快速且简单的解决方案
创建一个Label
,其中包含重复的下划线字符,并将其定位在登录TextBox
的底部:
txtName.BorderStyle = BorderStyle.None;
Label lblBottomBorder = new Label();
lblBottomBorder.ForeColor = Color.Blue;
lblBottomBorder.Width = txtName.Width + 8;
lblBottomBorder.Text = new String('_', 250);
lblBottomBorder.Location = new Point(txtName.Location.X - 3, txtName.Location.Y + 3);
Controls.Add(lblBottomBorder);
编辑:
第二种更灵活的解决方案
覆盖Form.OnPaint()
方法,并使用Graphics.DrawLine()
方法在登录TextBox
下面绘制自定义线条:
public partial class FrmLogin : Form
{
public FrmLogin()
{
InitializeComponent();
Text = "Login";
StartPosition = FormStartPosition.CenterScreen;
MaximizeBox = false;
MinimizeBox = false;
FormBorderStyle = FormBorderStyle.FixedDialog;
Font = new Font("Segoe UI", 10);
BackColor = Color.White;
AcceptButton = btnOK;
Activated += (sender, e) => txtEmail.PlaceholderText = "Email, phone or Skype";
lblEnter.Font = new Font("Segoe UI", 14, FontStyle.Bold);
txtEmail.BorderStyle = BorderStyle.None;
txtEmail.ForeColor = Color.DimGray;
btnOK.BackColor = Color.DarkBlue;
btnOK.ForeColor = Color.White;
}
protected override void OnPaint(PaintEventArgs e)
{
Point txtEmailLocation = PointToClient(PointToScreen(txtEmail.Location));
var lineStart = new Point(txtEmailLocation.X, txtEmailLocation.Y + txtEmail.Height + 7);
var lineEnd = new Point(txtEmailLocation.X + txtEmail.Width, txtEmailLocation.Y + txtEmail.Height + 7);
Pen pen = new Pen(Color.Blue) { Width = 2 };
e.Graphics.DrawLine(pen, lineStart, lineEnd);
}
}
请注意,TextBox.PlaceholderText
属性需要.NET 5+。登录表单的屏幕截图如下:
虽然不像Microsoft页面那样优雅,但能完成任务。
英文:
First, quick and dirty solution
Create a Label
with repeated underscore characters and locate it at the bottom of the login TextBox
:
txtName.BorderStyle = BorderStyle.None;
Label lblBottomBorder = new Label();
lblBottomBorder.ForeColor = Color.Blue;
lblBottomBorder.Width = txtName.Width + 8;
lblBottomBorder.Text = new String('_', 250);
lblBottomBorder.Location = new Point(txtName.Location.X - 3, txtName.Location.Y + 3);
Controls.Add(lblBottomBorder);
EDIT:
Second and more flexible solution
Override the Form.OnPaint()
method and draw a custom line under the login TextBox
using the Graphics.DrawLine()
method:
public partial class FrmLogin : Form
{
public FrmLogin()
{
InitializeComponent();
Text = "Login";
StartPosition = FormStartPosition.CenterScreen;
MaximizeBox = false;
MinimizeBox = false;
FormBorderStyle = FormBorderStyle.FixedDialog;
Font = new Font("Segoe UI", 10);
BackColor = Color.White;
AcceptButton = btnOK;
Activated += (sender, e) => txtEmail.PlaceholderText = "Email, phone or Skype";
lblEnter.Font = new Font("Segoe UI", 14, FontStyle.Bold);
txtEmail.BorderStyle = BorderStyle.None;
txtEmail.ForeColor = Color.DimGray;
btnOK.BackColor = Color.DarkBlue;
btnOK.ForeColor = Color.White;
}
protected override void OnPaint(PaintEventArgs e)
{
Point txtEmailLocation = PointToClient(PointToScreen(txtEmail.Location));
var lineStart = new Point(txtEmailLocation.X, txtEmailLocation.Y + txtEmail.Height + 7);
var lineEnd = new Point(txtEmailLocation.X + txtEmail.Width, txtEmailLocation.Y + txtEmail.Height + 7);
Pen pen = new Pen(Color.Blue) { Width = 2 };
e.Graphics.DrawLine(pen, lineStart, lineEnd);
}
}
Please note that the TextBox.PlaceholderText
property requires .NET 5+. The screenshot of the login form is:
Not as elegant as the Microsoft page but it gets the job done.
答案2
得分: 2
尝试使用这个简单的UserControl。它只包含一个标准的TextBox控件,并添加了一些属性来定义新的行为。
- 它提供了自定义绘制背景以显示底部可调整大小的线条
- 允许更改底线的颜色
- 根据当前TextBox的大小自动调整大小(例如,当您更改字体时)
- 可以设置Cue Banner(灰色文本),当文本为空时
- 允许设置输入框用于输入密码时的替换字符
- 允许右到左布局
当然,您可以随时添加其他内容(例如,添加一些图形元素相当简单)
要构建此UserControl:
- 向项目添加一个新的UserControl,命名为
TextBoxInput
(暂时命名为此) - 将其
Width
设置为150
- 将其
Padding
设置为(3, 10, 3, 1)
,并将BorderStyle
设置为None
- 将其
AutoScaleMode
设置为Dpi
- 添加一个TextBox,命名为
EditControl
,并将其停靠到Top
- 更改UserControl的
BackColor
和ForeColor
属性以匹配TextBox的属性 - 使用此处找到的代码替换代码文件中的内容(保留
namespace
) - 构建项目,在工具箱中找到您的UserControl,并将其拖放到窗体上
自定义设计器。仅用于删除一些无关的属性和对控件分配的默认文本(以便显示Cue Banner)。
要在.NET 5+应用程序中使用设计器,请通过NuGet包管理器安装Microsoft.WinForms.Designer.SDK支持。
public class TextBoxInputDesigner : ControlDesigner {
private readonly string[] RemovedProperties = new[] {
"AutoSize", "AutoSizeMode", "AutoScroll", "AutoScrollMargin", "AutoScrollMinSize",
"BackgroundImage", "BackgroundImageLayout", "Cursor"
};
public TextBoxInputDesigner() { }
public override void InitializeNewComponent(IDictionary defaultValues) {
base.InitializeNewComponent(defaultValues);
var descriptor = TypeDescriptor.GetProperties(Component)["Text"];
if (descriptor != null && (descriptor.PropertyType == typeof(string))) {
descriptor.SetValue(Component, string.Empty);
}
}
protected override void PreFilterProperties(IDictionary properties) {
foreach (string prop in RemovedProperties) {
properties.Remove(prop);
}
base.PreFilterProperties(properties);
}
}
这是它的工作原理:
英文:
Try out this simple UserControl. It just contains a standard TextBox Control and adds some properties to define the new behavior.
- It provides custom painting of the background to show a resizable line at the bottom
- Allows to change the Color of the bottom line
- Auto-sizes depending on the current TextBox size (e.g, when you change the Font)
- Can set a Cue Banner (grayed text) when the text is empty
- Allows to set a replacement char when the input box is used to enter a Password
- Allows Right-To-Left layout
You can of course add other stuff as you go (e.g., adding some graphic elements it's quite simple)
To build this UserControl:
- Add a new UserControl to the Project, name it
TextBoxInput
(for now) - Set its
Width
to150
- Set its
Padding
to(3, 10, 3, 1)
andBorderStyle = None
- Set its
AutoScaleMode = Dpi
- Add a TextBox, name it
EditControl
and dock it toTop
- Change the
BackColor
andForeColor
properties of the UserControl to match the TextBox's properties - Replace what's in the code file with the code you find here (preserving the
namespace
) - Build the Project, find your UserControl in the ToolBox and drop it on a Form
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(TextBoxInputDesigner))]
public partial class TextBoxInput : UserControl {
private string m_CueBanner = string.Empty;
private bool m_CueBannerShowOnFocus = true;
private Color m_LineColor = Color.CadetBlue;
private int m_LineDistance = 4;
private int m_LineHeight = 1;
public TextBoxInput() {
InitializeComponent();
ResizeRedraw = true;
Padding = new Padding(3, 10, 3, 1);
EditControl.TextChanged += (_, __) => OnTextChangedInternal(EditControl.Text, false);
EditControl.HandleCreated += (_, __) => SetCueBanner(EditControl.Handle, m_CueBanner, m_CueBannerShowOnFocus);
CueBanner = "<Enter CueBanner>";
}
public string CueBanner {
get => m_CueBanner;
set {
m_CueBanner = value;
SetCueBanner(EditControl.Handle, m_CueBanner, m_CueBannerShowOnFocus);
}
}
[DefaultValue(true)]
public bool CueBannerShowOnFocus {
get => m_CueBannerShowOnFocus;
set {
m_CueBannerShowOnFocus = value;
SetCueBanner(EditControl.Handle, m_CueBanner, m_CueBannerShowOnFocus);
}
}
public Color LineColor {
get => m_LineColor;
set {
m_LineColor = value;
Invalidate();
}
}
[DefaultValue(1), Description("Sets the height of the Line. Allowed values (1, 8)")]
public int LineHeight {
get => m_LineHeight;
set {
m_LineHeight = Math.Max(1, Math.Min(value, 8));
Invalidate();
OnResize(EventArgs.Empty);
}
}
[DefaultValue(false)]
public bool IsPassword {
get => EditControl.UseSystemPasswordChar;
set => EditControl.UseSystemPasswordChar = value;
}
[Bindable(true), Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override string Text {
get => base.Text;
set {
OnTextChangedInternal(value, true);
}
}
protected override void OnBackColorChanged(EventArgs e) {
base.OnBackColorChanged(e);
EditControl.BackColor = base.BackColor;
}
protected override void OnForeColorChanged(EventArgs e) {
base.OnForeColorChanged(e);
EditControl.ForeColor = base.ForeColor;
}
protected override void OnLayout(LayoutEventArgs e) {
base.OnLayout(e);
ClientSize = new Size(ClientSize.Width, EditControl.Bounds.Bottom + m_LineDistance + m_LineHeight + 1);
}
protected override void OnPaintBackground (PaintEventArgs e) {
base.OnPaintBackground(e);
int yPos = EditControl.Bounds.Bottom + m_LineDistance + (m_LineHeight / 2);
using (var pen = new Pen(m_LineColor, m_LineHeight)) {
e.Graphics.DrawLine(pen, 0, yPos, ClientSize.Width, yPos);
}
}
protected override void OnRightToLeftChanged(EventArgs e) {
base.OnRightToLeftChanged(e);
EditControl.RightToLeft = RightToLeft;
}
internal virtual void OnTextChangedInternal(string text, bool internalCall) {
base.Text = text;
if (internalCall) EditControl.Text = text;
OnTextChanged(EventArgs.Empty);
SetCueBanner(EditControl.Handle, m_CueBanner, m_CueBannerShowOnFocus);
}
public void SetCueBanner(IntPtr handle, string text, bool showOnFocus) {
if (handle != IntPtr.Zero) {
SendMessage(handle, EM_SETCUEBANNER, showOnFocus ? 1 : 0, text);
}
}
private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, string lParam);
}
Custom designer. This is used just to remove some irrelevant properties and the default text assigned to a Control (so the Cue Banner is shown instead).
To use the designer in a .NET 5+ application, install, via NuGetPackage Manager, the Microsoft.WinForms.Designer.SDK support.
public class TextBoxInputDesigner : ControlDesigner {
private readonly string[] RemovedProperties = new[] {
"AutoSize", "AutoSizeMode", "AutoScroll", "AutoScrollMargin","AutoScrollMinSize",
"BackgroundImage", "BackgroundImageLayout", "Cursor"
};
public TextBoxInputDesigner() { }
public override void InitializeNewComponent(IDictionary defaultValues) {
base.InitializeNewComponent(defaultValues);
var descriptor = TypeDescriptor.GetProperties(Component)["Text"];
if (descriptor != null && (descriptor.PropertyType == typeof(string))) {
descriptor.SetValue(Component, string.Empty);
}
}
protected override void PreFilterProperties(IDictionary properties) {
foreach (string prop in RemovedProperties) {
properties.Remove(prop);
}
base.PreFilterProperties(properties);
}
}
This is how it works:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论