2009-11-19 115 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;