ToolStripProfessionalRenderer スタイルはとても気に入っていますが、ToolStripTextBox をレンダリングする方法は好きではありません。ここで、ToolStripSystemRenderer はより良い仕事をします。両方のレンダラーの動作を組み合わせて、テキスト ボックスにシステム スタイルを使用し、その他すべてにプロ スタイルを使用する方法はありますか? ボタンにはプロ スタイルを、残りにはシステム スタイルを使用することに成功しました (両方のクラスを派生させることにより)。しかし、ToolStrip のテキスト ボックスはレンダラーによって処理されないようです。.NET Reflector を使用すると、ToolStrip.OnPaint メソッドによって呼び出されますが、これらのテキスト ボックスには Paint イベント ハンドラーがないように見えます。このようなテキスト ボックスを描画するためのコードはどこにあるのか、他のすべてのテキスト ボックスと同様にテキスト ボックスを描画するように構成するにはどうすればよいのか、疑問に思っています。
2 に答える
If you just want system rendering, the easiest approach is to use ToolStripControlHost instead:
class ToolStripSystemTextBox : ToolStripControlHost { public ToolStripSystemTextBox : base(new TextBox()) { } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [TypeConverter(typeof(ExpandableObjectConverter))] public TextBox TextBox { get { return Control as TextBox; } } }
I've taken the easy way out here and exposed the underlying TextBox directly to the form designer, instead of delegating all its properties. Obviously you can write all the property delgation code if you want.
On the other hand, if anyone wants to do truly custom rendering, I'll tell you what ToolStripTextBox does. Instead of hosting a TextBox directly, it hosts a private derived class called ToolStripTextBoxControl. This class overrides its WndProc in order to directly handle WM_NCPAINT. And then instead of delegating the actual drawing to the Renderer, it checks the Renderer's Type, and then branches to different rendering code inside of ToolStripTextBoxControl. It's pretty ugly.
「WndProc」に飛び込む必要もないかもしれません。これはそれなしで行われました:
問題は、j__m で説明されているように、ToolStripControlHost を使用してツール ストリップでカスタム コントロールをホストできるため、「見栄えの良い」TextBox をどのように作成するかです。
詳細はこちら: http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripcontrolhost.aspx
文書化されているように、使用するコントロールはカスタム コントロールにすることができます。
まず、カスタム TextBox コントロールを作成するのは非常に難しいです。行きたい場合:
public partial class TextBoxOwnerDraw : TextBox
あなたは大きな問題に直面しています!しかし、そうである必要はありません。ここにちょっとしたトリックがあります:
カスタム コントロールを Panel として作成し、TextBox を Panel に追加し、Textbox の境界線を None に設定すると、上記の結果が得られます。何よりも、通常の古い TextBox だけなので、カットしてください。すべての作品をコピーして貼り付け、右クリックで動作します!
OK、見栄えの良いテキストボックスのコードは次のとおりです。
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 にアクセスするときに覚えておくべきことは 1 つだけです。
tBox.ToolStripTextBox.Text;