2009-11-19 52 views
2

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

+0

的WinForms或WPF? – Oskar 2009-11-19 10:08:11

+0

Windows窗体 - [分钟。 15个字符的计算器] – ygoe 2010-12-23 12:33:28

回答

3

如果你只是想系统的渲染,最简单的方法是使用ToolStripControlHost代替:

 
class ToolStripSystemTextBox : ToolStripControlHost 
{ 
    public ToolStripSystemTextBox : base(new TextBox()) { } 

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    public TextBox TextBox { get { return Control as TextBox; } } 
} 

我已经采取了这里的简单的方法,直接暴露潜在的文本框窗体设计器,而不是委托所有的属性。显然你可以编写所有的财产分类代码,如果你想。另一方面,如果有人想做真正的定制渲染,我会告诉你什么是ToolStripTextBox。它不直接托管文本框,而是托管一个名为ToolStripTextBoxControl的私有派生类。该类重写它的WndProc以直接处理WM_NCPAINT。然后将实际绘图委托给渲染器,然后检查渲染器的类型,然后分支到ToolStripTextBoxControl中的不同渲染代码。这很丑陋。

1

也可能没有必要潜入“WndProc”。这是没有完成它:

This was done without "WndProc"

真正的问题是你如何做一个“好看”文本框,因为j__m所描述的,你可以只使用ToolStripControlHost,在您的工具来承载自定义控件跳闸。

这里更多: http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripcontrolhost.aspx

而作为记录,您可以使用该控件可以是自定义控制。首先,制作一个自定义的TextBox控件是非常棘手的。如果你想去:

public partial class TextBoxOwnerDraw : TextBox 

你是在为巨大的麻烦!但它不一定是。这里有一个小技巧:

如果您将自定义控件设置为Panel,然后将TextBox添加到Panel中,然后将Textbox边框设置为None ...您可以实现上述结果,并且最重要的是,它只是一个普通的旧文本框,所以剪贴复制粘贴全部作品,右键单击作品!

好吧,这里是一个很好看的文本框代码:

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中,预览窗口支持渲染此控件。

只有一件事要记住,它与实际的文本访问文本框时,它的:

tBox.ToolStripTextBox.Text;