views:

110

answers:

2

I'm using a ButtonRenderer to draw a button in a custom cell. I'd like the button to have a nonstandard BackColor. This is supported by normal buttons, but there's nothing in button cells or ButtonRenderer to support it. How do I draw a button with a nonstandard BackColor? The method has to take the user's theme into account - I can't just draw my own button.

+2  A: 

ButtonRenderer uses VisualStyleRenderer.DrawBackground() to draw the button background. That method is very much aware of the user selected theme, the button's background will use the colors specified by the theme. Using a non-standard BackColor would violate the user selected theme. You can't have it both ways.

The Button class doesn't actually use ButtonRenderer, it uses one of three renderers derived from the internal ButtonBaseAdapter class in the System.Windows.Forms.ButtonInternal namespace. These renderers are internal, you can't use them in your own code. Take a look at them with Reflector or the Reference Source to see what it takes. Focus on the PaintButtonBackground method.

Hans Passant
It was ButtonStandardAdapter.PaintThemedButtonBackground that turned out to be the crucial one - it calls ButtonRender.DrawButton, then shrinks the rectangle by 4px, regardless of theme.
Simon
A: 

Paint your own button using the ControlPaint and TextRenderer class supplied. It is fairly straightforward. I put these code together quickly to show you. You can beautify the look of the button by setting the border style and etc.

    private ButtonState state = ButtonState.Normal;
    public ButtonCell(): base()
    {
        this.Size = new Size(100, 40);
        this.Location = new Point(50, 50);
        this.Font = SystemFonts.IconTitleFont;
        this.Text = "Click here";     
    }
    private void DrawFocus()
    {
        Graphics g = Graphics.FromHwnd(this.Handle);
        Rectangle r = Rectangle.Inflate(this.ClientRectangle, -4, -4);
        ControlPaint.DrawFocusRectangle(g, r);
        g.Dispose();
    }
    private void DrawFocus(Graphics g)
    {
        Rectangle r = Rectangle.Inflate(this.ClientRectangle, -4, -4);
        ControlPaint.DrawFocusRectangle(g, r);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (state == ButtonState.Pushed)
            ControlPaint.DrawBorder3D(e.Graphics, e.ClipRectangle, Border3DStyle.Sunken);
        else
            ControlPaint.DrawBorder3D(e.Graphics, e.ClipRectangle, Border3DStyle.Raised);
        TextRenderer.DrawText(e.Graphics, Text, this.Font, e.ClipRectangle, this.ForeColor,
            TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
    }
    protected override void OnGotFocus(EventArgs e)
    {
        DrawFocus();
        base.OnGotFocus(e);
    }
    protected override void OnLostFocus(EventArgs e)
    {
        Invalidate();
        base.OnLostFocus(e);
    }
    protected override void OnMouseEnter(EventArgs e)
    {
        DrawFocus();
        base.OnMouseEnter(e);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        Invalidate();
        base.OnMouseLeave(e);
    }
    protected override void OnMouseDown(MouseEventArgs e)
    {
        state = ButtonState.Pushed;
        Invalidate();
        base.OnMouseDown(e);
    }
    protected override void OnMouseUp(MouseEventArgs e)
    {
        state = ButtonState.Normal;
        Invalidate();
        base.OnMouseUp(e);
    }
Fadrian Sudaman
ControlPaint draws an unthemed button - as I said in the question, I have to take the user's theme into account - I can't just draw my own button.
Simon
Sorry I missed out on that. From the post above you seem to find why it doesnt allow the background repaint, but have you found a solution? Will be interested to learn from it as well.
Fadrian Sudaman
Yeah - as nobugz suggested, I used the reflector to see how Button does it.
Simon