2009-11-19 5 views
2

ToolStripProfessionalRenderer 스타일이 상당히 마음에 들지만 ToolStripTextBox를 렌더링하는 방식이 마음에 들지 않습니다. 여기에서 ToolStripSystemRenderer는 IMO를 더 잘 수행합니다. 이제는 텍스트 상자에 시스템 스타일을 사용하고 다른 모든 것에는 프로 스타일을 사용하는 두 렌더러의 동작을 결합하는 방법이 있습니까? 나는 버튼과 시스템 스타일을위한 프로 스타일을 (두 클래스 모두를 파생시킴으로써) 성공적으로 사용할 수 있었다. 그러나 ToolStrip의 텍스트 상자는 렌더러에서 처리하지 않는 것 같습니다. .NET Reflector를 사용하면 이러한 텍스트 상자는 ToolStrip.OnPaint 메서드에 의해 호출되었지만 Paint 이벤트 처리기가없는 것처럼 보입니다. 같은 텍스트 상자를 그리는 코드가 어디에 있고, 다른 모든 텍스트 상자와 마찬가지로 텍스트 상자를 그리는 방법을 궁금합니다.ToolStripTextBox의 렌더링을 사용자 정의하는 방법은 무엇입니까?

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

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

내가 대신 위임, 여기에서 밖으로 쉬운 방법을 가지고 폼 디자이너에 직접 기본 텍스트 상자를 노출 한 : 당신은 단지 시스템 렌더링을 원하는 경우에

+0

을 WinForms 또는 WPF는? – Oskar

+0

Windows Forms - [분. 15자를위한 stackoverflow] – ygoe

답변

3

는 가장 쉬운 방법 대신 ToolStripControlHost를 사용하는 것입니다 모든 속성. 원하는 경우 분명히 모든 부동산 변경 코드를 작성할 수 있습니다.

진정으로 사용자 정의 렌더링을 원한다면 ToolStripTextBox의 기능에 대해 알려 드리겠습니다. TextBox를 직접 호스팅하는 대신 ToolStripTextBoxControl이라는 개인 파생 클래스를 호스팅합니다. 이 클래스는 WM_NCPAINT를 직접 처리하기 위해 WndProc를 재정의합니다. 그런 다음 실제 드로잉을 Renderer에 위임하는 대신 Renderer의 Type을 확인한 다음 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 

당신은 큰 문제가 있습니다! 그러나 반드시 그렇게 할 필요는 없습니다. 여기에 약간의 트릭이 있습니다 :

사용자 정의 컨트롤을 패널로 만든 다음 패널에 TextBox를 추가 한 다음 텍스트 상자 테두리를 없음으로 설정하면 위와 같이 결과를 얻을 수 있습니다. , 그것의 다만 일정한 오래되는 TextBox, 그래서 커트 사본은 모든 일을 풀칠하고, 오른쪽 누르기 일한다!

좋아, 여기에 멋진 찾고 텍스트 상자에 대한 코드는 다음 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; 
    } 
} 

지금

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 

} 

그런 다음 당신은 단지 도구 모음에 추가, 그것을 사용하려는 경우 :

ToolStripTextBoxOwnerDraw tBox = new ToolStripTextBoxOwnerDraw(); 
this.toolStripMain.Items.Add(tBox); 

그러나 추가하고 싶습니다.Visual Studio의 경우 미리보기 창에서이 컨트롤의 렌더링을 지원합니다.

, 그 안에 실제 텍스트는 텍스트 상자에 액세스 할 때 기억해야 할 단 한 가지가있다 :

tBox.ToolStripTextBox.Text;