我非常喜欢 ToolStripProfessionalRenderer 样式,但我不喜欢它呈现 ToolStripTextBox 的方式。在这里,ToolStripSystemRenderer 在 IMO 上做得更好。现在有没有办法将两个渲染器的行为结合起来,为文本框使用系统样式,为其他所有内容使用专业样式?我已经成功地成功地使用专业风格的按钮和系统风格的其余部分(通过派生两个类)。但是 ToolStrip 中的文本框似乎没有由渲染器处理。使用 .NET Reflector,这些文本框甚至似乎都没有 Paint 事件处理程序,尽管它是由 ToolStrip.OnPaint 方法调用的。我想知道绘制这样一个文本框的代码在哪里,以及如何配置它来像所有其他文本框一样绘制一个文本框。
2 回答
如果您只想要系统渲染,最简单的方法是使用 ToolStripControlHost 代替:
类 ToolStripSystemTextBox : ToolStripControlHost { 公共工具条系统文本框:基础(新文本框()){} [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [TypeConverter(typeof(ExpandableObjectConverter))] public TextBox TextBox { get { return Control as TextBox; } } }
我在这里采取了简单的方法,将底层的 TextBox 直接暴露给表单设计器,而不是委托它的所有属性。显然,您可以根据需要编写所有属性委托代码。
另一方面,如果有人想做真正的自定义渲染,我会告诉你 ToolStripTextBox 做了什么。它不是直接托管 TextBox,而是托管一个名为 ToolStripTextBoxControl 的私有派生类。此类重写其 WndProc 以便直接处理 WM_NCPAINT。然后它不是将实际绘图委托给渲染器,而是检查渲染器的类型,然后分支到 ToolStripTextBoxControl 内的不同渲染代码。这很丑陋。
也可能没有必要深入研究“WndProc”。这是在没有它的情况下完成的:
问题实际上是如何制作“漂亮”的文本框,因为如 j__m 所述,您可以使用 ToolStripControlHost 在工具条中托管自定义控件。
更多信息:http: //msdn.microsoft.com/en-us/library/system.windows.forms.toolstripcontrolhost.aspx
如文件所述,您使用的控件可以是自定义控件。
首先,制作自定义 TextBox 控件非常棘手。如果你想去:
public partial class TextBoxOwnerDraw : TextBox
你有大麻烦了!但不一定是这样。这里有一个小技巧:
如果您将自定义控件制作为面板,然后将文本框添加到面板,然后将文本框边框设置为无...您可以实现如上的结果,最重要的是,它只是一个普通的旧文本框,所以剪切复制粘贴所有作品,右键作品!
好的,这是一个漂亮的文本框的代码:
public partial class TextBoxOwnerDraw : Panel
{
private TextBox MyTextBox;
private int cornerRadius = 1;
private Color borderColor = Color.Black;
private int borderSize = 1;
private Size preferredSize = new Size(120, 25); // Use 25 for height, so it sits in the middle
/// <summary>
/// Access the textbox
/// </summary>
public TextBox TextBox
{
get { return MyTextBox; }
}
public int CornerRadius
{
get { return cornerRadius; }
set
{
cornerRadius = value;
RestyleTextBox();
this.Invalidate();
}
}
public Color BorderColor
{
get { return borderColor; }
set
{
borderColor = value;
RestyleTextBox();
this.Invalidate();
}
}
public int BorderSize
{
get { return borderSize; }
set
{
borderSize = value;
RestyleTextBox();
this.Invalidate();
}
}
public Size PrefSize
{
get { return preferredSize; }
set
{
preferredSize = value;
RestyleTextBox();
this.Invalidate();
}
}
public TextBoxOwnerDraw()
{
MyTextBox = new TextBox();
this.Controls.Add(MyTextBox);
RestyleTextBox();
}
private void RestyleTextBox()
{
double TopPos = Math.Floor(((double)this.preferredSize.Height / 2) - ((double)MyTextBox.Height / 2));
MyTextBox.BackColor = Color.White;
MyTextBox.BorderStyle = BorderStyle.None;
MyTextBox.Multiline = false;
MyTextBox.Top = (int)TopPos;
MyTextBox.Left = this.BorderSize;
MyTextBox.Width = preferredSize.Width - (this.BorderSize * 2);
this.Height = MyTextBox.Height + (this.BorderSize * 2); // Will be ignored, but if you use elsewhere
this.Width = preferredSize.Width;
}
protected override void OnPaint(PaintEventArgs e)
{
if (cornerRadius > 0 && borderSize > 0)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle cRect = this.ClientRectangle;
Rectangle safeRect = new Rectangle(cRect.X, cRect.Y, cRect.Width - this.BorderSize, cRect.Height - this.BorderSize);
// Background color
using (Brush bgBrush = new SolidBrush(MyTextBox.BackColor))
{
DrawRoundRect(g, bgBrush, safeRect, (float)this.CornerRadius);
}
// Border
using (Pen borderPen = new Pen(this.BorderColor, (float)this.BorderSize))
{
DrawRoundRect(g, borderPen, safeRect, (float)this.CornerRadius);
}
}
base.OnPaint(e);
}
#region Private Methods
private GraphicsPath getRoundRect(int x, int y, int width, int height, float radius)
{
GraphicsPath gp = new GraphicsPath();
gp.AddLine(x + radius, y, x + width - (radius * 2), y); // Line
gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90); // Corner (Top Right)
gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2)); // Line
gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90); // Corner (Bottom Right)
gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height); // Line
gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90); // Corner (Bottom Left)
gp.AddLine(x, y + height - (radius * 2), x, y + radius); // Line
gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner (Top Left)
gp.CloseFigure();
return gp;
}
private void DrawRoundRect(Graphics g, Pen p, Rectangle rect, float radius)
{
GraphicsPath gp = getRoundRect(rect.X, rect.Y, rect.Width, rect.Height, radius);
g.DrawPath(p, gp);
gp.Dispose();
}
private void DrawRoundRect(Graphics g, Pen p, int x, int y, int width, int height, float radius)
{
GraphicsPath gp = getRoundRect(x, y, width, height, radius);
g.DrawPath(p, gp);
gp.Dispose();
}
private void DrawRoundRect(Graphics g, Brush b, int x, int y, int width, int height, float radius)
{
GraphicsPath gp = getRoundRect(x, y, width, height, radius);
g.FillPath(b, gp);
gp.Dispose();
}
private void DrawRoundRect(Graphics g, Brush b, Rectangle rect, float radius)
{
GraphicsPath gp = getRoundRect(rect.X, rect.Y, rect.Width, rect.Height, radius);
g.FillPath(b, gp);
gp.Dispose();
}
#endregion
}
现在为 ToolStripControlHost
public partial class ToolStripTextBoxOwnerDraw : ToolStripControlHost
{
private TextBoxOwnerDraw InnerTextBox
{
get { return Control as TextBoxOwnerDraw; }
}
public ToolStripTextBoxOwnerDraw() : base(new TextBoxOwnerDraw()) { }
public TextBox ToolStripTextBox
{
get { return InnerTextBox.TextBox; }
}
public int CornerRadius
{
get { return InnerTextBox.CornerRadius; }
set
{
InnerTextBox.CornerRadius = value;
InnerTextBox.Invalidate();
}
}
public Color BorderColor
{
get { return InnerTextBox.BorderColor; }
set
{
InnerTextBox.BorderColor = value;
InnerTextBox.Invalidate();
}
}
public int BorderSize
{
get { return InnerTextBox.BorderSize; }
set
{
InnerTextBox.BorderSize = value;
InnerTextBox.Invalidate();
}
}
public override Size GetPreferredSize(Size constrainingSize)
{
return InnerTextBox.PrefSize;
}
}
然后当你想使用它时,只需将它添加到工具栏:
ToolStripTextBoxOwnerDraw tBox = new ToolStripTextBoxOwnerDraw();
this.toolStripMain.Items.Add(tBox);
或者你想添加它。如果您在 Visual Studio 中,预览窗口支持呈现此控件。
只有一件事要记住,当使用其中的实际文本访问 TextBox 时,它:
tBox.ToolStripTextBox.Text;