Как настроить рендеринг ToolStripTextBox? - PullRequest
3 голосов
/ 19 ноября 2009

Мне очень нравится стиль ToolStripProfessionalRenderer, но мне не нравится, как он отображает ToolStripTextBox. Здесь ToolStripSystemRenderer делает лучшую работу IMO. Есть ли способ объединить поведение обоих средств визуализации, чтобы использовать системный стиль для текстовых полей и профессиональный стиль для всего остального? Мне успешно удалось использовать про стиль для кнопок и стиль системы для остальных (выводя оба класса). Но текстовые поля в ToolStrip, похоже, не обрабатываются средством визуализации. При использовании .NET Reflector эти текстовые поля даже не имеют обработчика событий Paint, хотя он вызывается методом ToolStrip.OnPaint. Мне интересно, где вообще код для рисования такого текстового поля и как его можно настроить для рисования текстового поля, как и всех других текстовых полей.

Ответы [ 2 ]

4 голосов
/ 14 января 2011

Если вам просто нужен системный рендеринг, самый простой подход - использовать ToolStripControlHost:

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

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

Я выбрал легкий путь и открыл основной TextBox непосредственно для дизайнера форм, вместо того, чтобы делегировать все его свойства. Очевидно, что вы можете написать весь код разграничения свойств, если хотите.

С другой стороны, если кто-то захочет сделать действительно индивидуальный рендеринг, я расскажу вам, что делает ToolStripTextBox. Вместо непосредственного размещения TextBox, он содержит частный производный класс с именем ToolStripTextBoxControl. Этот класс переопределяет свой WndProc для прямой обработки WM_NCPAINT. И затем вместо того, чтобы делегировать фактический чертеж в Renderer, он проверяет тип Renderer и затем переходит на другой код рендеринга внутри ToolStripTextBoxControl. Это довольно некрасиво.

1 голос
/ 24 июля 2013

Возможно, нет необходимости погружаться в «WndProc». Это было сделано без него:

This was done without

Вопрос на самом деле в том, как создать «красивый» TextBox, потому что, как описано в j__m, вы можете просто использовать ToolStripControlHost, чтобы разместить пользовательский элемент управления на панели инструментов.

Подробнее здесь: http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripcontrolhost.aspx

И как задокументировано, используемый вами элемент управления может быть пользовательским элементом управления.

Во-первых, безумно сложно создать собственный элемент управления TextBox. Если вы хотите пойти:

public partial class TextBoxOwnerDraw : TextBox

Вас ждут ОГРОМНЫЕ неприятности! Но это не должно быть. Вот небольшая хитрость:

Если вы создадите пользовательский элемент управления в качестве панели, затем добавите TextBox на панель, а затем установите для границ текстового поля значение None ... вы можете получить результат, как описано выше, и, что лучше всего, просто обычный старый 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;
...