3

我非常喜欢 ToolStripProfessionalRenderer 样式,但我不喜欢它呈现 ToolStripTextBox 的方式。在这里,ToolStripSystemRenderer 在 IMO 上做得更好。现在有没有办法将两个渲染器的行为结合起来,为文本框使用系统样式,为其他所有内容使用专业样式?我已经成功地成功地使用专业风格的按钮和系统风格的其余部分(通过派生两个类)。但是 ToolStrip 中的文本框似乎没有由渲染器处理。使用 .NET Reflector,这些文本框甚至似乎都没有 Paint 事件处理程序,尽管它是由 ToolStrip.OnPaint 方法调用的。我想知道绘制这样一个文本框的代码在哪里,以及如何配置它来像所有其他文本框一样绘制一个文本框。

4

2 回答 2

4

如果您只想要系统渲染,最简单的方法是使用 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 内的不同渲染代码。这很丑陋。

于 2011-01-14T07:11:22.100 回答
1

也可能没有必要深入研究“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;
于 2013-07-24T11:51:35.707 回答