preload
Sep 01

Adding gradient details to your application graphic can make a big difference. The out-of-box support for this in Compact Framework is not very good and you need to custom build controls with gradient support. This post explains how to create your own gradient buttons in .NET Compact Framework.

I have earlier written a post about Creating gradient background with transparent labels in .NET Compact Framework and the approach when creating a gradient button is quite similar. As a base for drawing gradient I use the same GradientFill.cs and Win32Helper.cs that I used and explained when creating gradient background.

The GradientFill.cs and Win32Helper.cs I have got from Microsoft MSDN site: How to Display a Gradient Fill. Their example also have a gradient button, but the example I will show here is a very simple gradient button that is easy to continue developing to suite your needs.

GradientFill.cs

using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;

<span id="more-1851"></span>

namespace TechCon.UI
{
    public sealed class GradientFill
    {
        // This method wraps the PInvoke to GradientFill.
        // Parmeters:
        //  gr - The Graphics object we are filling
        //  rc - The rectangle to fill
        //  startColor - The starting color for the fill
        //  endColor - The ending color for the fill
        //  fillDir - The direction to fill
        //
        // Returns true if the call to GradientFill succeeded; false
        // otherwise.
        public static bool Fill(
            Graphics gr,
            Rectangle rc,
            Color startColor, Color endColor,
            FillDirection fillDir)
        {
            // Initialize the data to be used in the call to GradientFill.
            var tva = new Win32Helper.TRIVERTEX[2];
            tva[0] = new Win32Helper.TRIVERTEX(rc.X, rc.Y, startColor);
            tva[1] = new Win32Helper.TRIVERTEX(rc.Right, rc.Bottom, endColor);
            var gra = new[]
                          {
                              new Win32Helper.GRADIENT_RECT(0, 1)
                          };

            // Get the hDC from the Graphics object.
            IntPtr hdc = gr.GetHdc();

            // PInvoke to GradientFill.
            bool b;

            b = Win32Helper.GradientFill(
                hdc,
                tva,
                (uint)tva.Length,
                gra,
                (uint)gra.Length,
                (uint)fillDir);
            Debug.Assert(b, string.Format(
                                &quot;GradientFill failed: {0}&quot;,
                                Marshal.GetLastWin32Error()));

            // Release the hDC from the Graphics object.
            gr.ReleaseHdc(hdc);

            return b;
        }

        // The direction to the GradientFill will follow
        public enum FillDirection
        {
            //
            // The fill goes horizontally
            //
            LeftToRight = Win32Helper.GRADIENT_FILL_RECT_H,
            //
            // The fill goes vertically
            //
            TopToBottom = Win32Helper.GRADIENT_FILL_RECT_V
        }
    }
}

Win32Helper.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace TechCon.UI
{
    public sealed class Win32Helper
    {
        public struct TRIVERTEX
        {
            public int x;
            public int y;
            public ushort Red;
            public ushort Green;
            public ushort Blue;
            public ushort Alpha;

            public TRIVERTEX(int x, int y, Color color)
                : this(x, y, color.R, color.G, color.B, color.A)
            {
            }

            public TRIVERTEX(
                int x, int y,
                ushort red, ushort green, ushort blue,
                ushort alpha)
            {
                this.x = x;
                this.y = y;
                Red = (ushort) (red << 8);
                Green = (ushort) (green << 8);
                Blue = (ushort) (blue << 8);
                Alpha = (ushort) (alpha << 8);
            }
        }

        public struct GRADIENT_RECT
        {
            public uint UpperLeft;
            public uint LowerRight;

            public GRADIENT_RECT(uint ul, uint lr)
            {
                UpperLeft = ul;
                LowerRight = lr;
            }
        }


        [DllImport("coredll.dll", SetLastError = true, EntryPoint = "GradientFill")]
        public static extern bool GradientFill(
            IntPtr hdc,
            TRIVERTEX[] pVertex,
            uint dwNumVertex,
            GRADIENT_RECT[] pMesh,
            uint dwNumMesh,
            uint dwMode);

        public const int GRADIENT_FILL_RECT_H = 0x00000000;
        public const int GRADIENT_FILL_RECT_V = 0x00000001;
    }
}

I have created a Custom Control class for the gradient button. This control will draw a gradient background, border, thick boarder when clicked and centred text.

GradientButton.cs

using System.Drawing;
using System.Windows.Forms;

namespace TechCon.UI.Controls
{
    public partial class GradientButton : Control
    {
        private Color _borderColor = Color.FromArgb(0x333333);
        private Color _borderColorSelected = Color.FromArgb(0x339966);
        private Color _gradientStartColor = Color.FromArgb(0xCCCCFF); //Color.FromArgb(0xA1BAC4));
        private Color _gradientEndColor = Color.FromArgb(0x336699); //Color.FromArgb(0x41939D);
        private GradientFill.FillDirection _gradientFillDirection = GradientFill.FillDirection.TopToBottom;

        public Color GradientStartColor
        {
            get { return _gradientStartColor; }
            set { _gradientStartColor = value; }
        }

        public Color GradientEndColor
        {
            get { return _gradientEndColor; }
            set { _gradientEndColor = value; }
        }

        public GradientFill.FillDirection GradientFillDirection
        {
            get { return _gradientFillDirection; }
            set { _gradientFillDirection = value; }
        }

        private bool _isSelected;

        public Color BorderColorSelected
        {
            get { return _borderColorSelected; }
            set { _borderColorSelected = value; }
        }

        public Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; }
        }

        public GradientButton()
        {
            InitializeComponent();
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            Graphics graphics = pe.Graphics;

            //Draw gradient background
            GradientFill.Fill(graphics, ClientRectangle, GradientStartColor, GradientEndColor,
                              GradientFillDirection);
            //Draw solid border
            if (_isSelected)
            {
                //Draw thick border with selected color
                graphics.DrawRectangle(new Pen(BorderColorSelected, 4), 2, 2,
                                       ClientRectangle.Width - 5, ClientRectangle.Height - 5);
            }
            else
            {
                //Draw normal border
                graphics.DrawRectangle(new Pen(BorderColor, 2), 1, 1,
                                       ClientRectangle.Width - 3, ClientRectangle.Height - 3);
            }

            //Draw text centered
            SizeF textSize = graphics.MeasureString(Text, Font);
            int left = Width/2 - (int) textSize.Width/2;
            int top = Height/2 - (int) textSize.Height/2;
            var rect = new Rectangle(ClientRectangle.Left + left,
                                     ClientRectangle.Top + top, (int) textSize.Width,
                                     (int) textSize.Height);
            graphics.DrawString(Text, Font,
                                new SolidBrush(ForeColor), rect);
        }


        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            //Leaving out OnPaintBackground will help avoid flickering
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            _isSelected = true;
            Invalidate();
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            _isSelected = false;
            Invalidate();
            base.OnMouseUp(e);
        }
    }
}

Using the GradientButton is very simple and under you will see how to create a top to bottom gradient button and a left to right gradient button.

            //Top to bottom gradient button
            GradientButton gradientButton = new GradientButton();
            gradientButton.ForeColor = Color.FromArgb(0xffffff);
            gradientButton.Location = new Point(40, 40);
            gradientButton.Size = new Size(160, 60);
            gradientButton.Text = "Gradient Button";
            gradientButton.Font = new Font(FontFamily.GenericSerif, 14, FontStyle.Regular);
            Controls.Add(gradientButton);

            //Left to right gradient button
            GradientButton gradientButtonLeftToRight = new GradientButton();
            gradientButtonLeftToRight.ForeColor = Color.FromArgb(0xffffff);
            gradientButtonLeftToRight.Location = new Point(40, 160);
            gradientButtonLeftToRight.Size = new Size(160, 60);
            gradientButtonLeftToRight.Text = "Gradient Button";
            gradientButtonLeftToRight.Font = new Font(FontFamily.GenericSerif, 14, FontStyle.Regular);
            gradientButtonLeftToRight.GradientFillDirection = GradientFill.FillDirection.LeftToRight;
            Controls.Add(gradientButtonLeftToRight);

As you can see the gradient is quite nice looking and it is just to find the right colors. Personally I like best when the gradient start and gradient end colors are closer than on the screenshot above. I just selected some colors so that the gradient effect would be easy to see.

Follow me on twitter @PerOla

Share & enjoy
You can subscribe to my comments feed to keep track of new comments.

2 Comments to “Creating gradient buttons in .NET Compact Framework”

  1. Sveinung Kval Bakken says:

    Android 😉

    android:background=”@drawable/filnavn”

  2. That is just to easy… where is the fun in that 😉

No Pingbacks to “Creating gradient buttons in .NET Compact Framework”

Leave a Reply

Subscribe to my comments feed

Subscribe to my feeds Follow me on Twitter
DZone MVB