Click here to Skip to main content
15,896,456 members
Articles / Programming Languages / C#

C# Windows Aero Style Wizard Control

Rate me:
Please Sign up or sign in to vote.
4.42/5 (11 votes)
14 Jun 2010GPL34 min read 79.2K   4.8K   42  
I have been a fan of the Windows Aero styled windows since Aero was first introduced in Windows Vista. However, there is little to no Aero inclusion in the .NET Framework, so I set out to create my own Windows Aero themed form.
//Copyright (C) 2010  Jonathan Preece
//
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using VistaControls.ThemeText;
using WindowsAeroWizardControl.Properties;

namespace WindowsAeroWizardControl
{
    ///<summary>
    /// Creates a Windows form that has all the properties necessary to create a Windows Aero enabled experience
    ///</summary>
    public class JPWizardForm : Form
    {
        #region Events

        ///<summary>
        /// Raised when the DWM notifies the form that Windows Aero has been disabled
        ///</summary>
        /// <remarks><para>DWM: Desktop Windows Manager</para></remarks>
        public event AeroGlassCompositionChanged DesktopCompositionChanged;

        /// <summary>
        /// Raised when the user clicks the "Next" button
        /// </summary>
        public event Generic Next;

        /// <summary>
        /// Raised when the user clicks the "Previous" button
        /// </summary>
        public event Generic Previous;

        /// <summary>
        /// Raised when the user clicks the "Cancel" button
        /// </summary>
        public event Generic CancelRequest;

        #endregion

        #region WindowThemeAttributeType enum

        ///<summary>
        /// WindowThemeAttributeType
        ///</summary>
        public enum WindowThemeAttributeType
        {
            ///<summary>
            /// WTA_NONCLIENT
            ///</summary>
            WTA_NONCLIENT = 1
        }

        #endregion

        #region External Methods

        ///<summary>
        /// Extends the window frame behind the client area.
        ///</summary>
        ///<param name="hWnd">The handle to the window for which the frame is extended into the client area.</param>
        ///<param name="Margins">A pointer to a MARGINS structure that describes the margins to use when extending the frame into the client area.</param>
        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS Margins);

        ///<summary>
        /// Obtains a value that indicates whether Desktop Window Manager (DWM) composition is enabled. Applications can listen for composition state changes by handling the WM_DWMCOMPOSITIONCHANGED notification.
        ///</summary>
        ///<returns>If desktop composition is enabled, returns true, otherwise false</returns>
        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern bool DwmIsCompositionEnabled();

        ///<summary>
        /// Sets attributes to control how visual styles are applied to a specified window.
        ///</summary>
        ///<param name="hWnd">Handle to a window to apply changes to.</param>
        ///<param name="wtype"></param>
        ///<param name="attributes"></param>
        ///<param name="size"></param>
        ///<returns>If the function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
        [DllImport("UxTheme.dll")]
        public static extern int SetWindowThemeAttribute(IntPtr hWnd, WindowThemeAttributeType wtype,
                                                         ref WTA_OPTIONS attributes, uint size);

        #endregion

        private const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
        private const int WM_DWMNCRENDERINGCHANGED = 0x031F;

        private const uint WTNCA_NODRAWCAPTION = 0x1;
        private const uint WTNCA_NODRAWICON = 0x2;

        private const string spaces = "                        ";
        private Button CancelRequestButton;
        private Panel FooterPanel;
        private Panel HeaderPanel;
        private PictureBox NavigationButton;
        private Button NextButton;
        private Label NoDWMLabel;
        private ThemedLabel WindowTitle;
        private PictureBox WizardIconPictureBox;
        private bool enablePreviousButton;

        #region Constructor

        ///<summary>
        /// Constructs the JPAeroForm class
        ///</summary>
        public JPWizardForm()
        {
            Load += JPAeroForm_Load;
            Resize += JPAeroForm_Resize;
        }

        private void JPAeroForm_Load(object sender, EventArgs e)
        {
            Color headerDefault = SystemColors.GradientActiveCaption;

            if (DwmIsCompositionEnabled() && !DesignMode)
            {
                var Margins = new MARGINS { Top = 41, Left = 0, Right = 0, Bottom = 0 };
                DwmExtendFrameIntoClientArea(Handle, ref Margins);

                var ops = new WTA_OPTIONS { Flags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON, Mask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON };
                SetWindowThemeAttribute(Handle, WindowThemeAttributeType.WTA_NONCLIENT, ref ops, (uint)Marshal.SizeOf(typeof(WTA_OPTIONS)));

                headerDefault = Color.Black;

                #region Set Window Title

                WindowTitle = new ThemedLabel { ShadowEnabled = true, TextAlignVertical = VerticalAlignment.Center, GlowSize = 6, Location = new Point(0, 1), Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right), Font = new Font("Corbel", 9.75f, FontStyle.Regular, GraphicsUnit.Point, 0), Size = new Size(602, 37), Text = spaces + Text, TabIndex = 5, Visible = true };
                Controls.Add(WindowTitle);

                #endregion
            }

            #region Create Panels

            HeaderPanel = new Panel { BackColor = headerDefault, Height = 41, Dock = DockStyle.Top };
            Controls.Add(HeaderPanel);
            HeaderPanel.SendToBack();

            FooterPanel = new Panel { BackColor = SystemColors.Control, Height = 45, Dock = DockStyle.Bottom };
            Controls.Add(FooterPanel);
            FooterPanel.SendToBack();

            #endregion

            #region 3D Lines

            var _3DLine1 = new JPLine { Dock = DockStyle.Top, ForeColor = Color.Gainsboro, Location = new Point(0, 0), Name = "_3DLine2", Size = new Size(544, 1), TabIndex = 8, Text = "_3DLine2" };

            FooterPanel.Controls.Add(_3DLine1);

            #endregion

            #region Buttons

            NextButton = new Button { DialogResult = DialogResult.OK, Location = new Point(381, 9), Name = "NextButton", Size = new Size(66, 26), TabIndex = 7, Text = "&Next", UseVisualStyleBackColor = true };
            NextButton.Click += NextButton_Click;

            FooterPanel.Controls.Add(NextButton);
            NextButton.BringToFront();

            CancelRequestButton = new Button { DialogResult = DialogResult.Cancel, Location = new Point(456, 9), Name = "CancelRequestButton", Size = new Size(66, 26), TabIndex = 7, Text = "&Cancel", UseVisualStyleBackColor = true };
            CancelRequestButton.Click += CancelRequestButton_Click;

            FooterPanel.Controls.Add(CancelRequestButton);
            CancelRequestButton.BringToFront();

            NavigationButton = new PictureBox { Image = Resources.disabled2, Location = new Point(2, 7), Name = "NavigationButton", Size = new Size(25, 25), SizeMode = PictureBoxSizeMode.Zoom, TabIndex = 6, TabStop = false, Tag = "disabled", BackColor = headerDefault };
            NavigationButton.MouseLeave += NavigationButton_MouseLeave;
            NavigationButton.Click += NavigationButton_Click;
            NavigationButton.MouseDown += NavigationButton_MouseDown;
            NavigationButton.MouseUp += NavigationButton_MouseUp;
            NavigationButton.MouseEnter += NavigationButton_MouseEnter;

            #endregion

            #region Other Visual Elements

            NoDWMLabel = new Label { AutoSize = true, BackColor = headerDefault, BorderStyle = BorderStyle.None, Font = new Font("Segoe UI", 8.75F), ForeColor = Color.Black, Location = new Point(66, 13), Name = "NoDWMLabel", Size = new Size(115, 17), TabIndex = 10, Text = "My Windows Aero Wizard" };

            WizardIconPictureBox = new PictureBox { BackColor = headerDefault, BorderStyle = BorderStyle.None, Location = new Point(39, 12), Name = "WizardIconPictureBox", Size = new Size(16, 16), SizeMode = PictureBoxSizeMode.Zoom, TabIndex = 9, TabStop = false, Image = Resources.wizard1616 };

            MinimumSize = new Size(455, 367);
            MaximizeBox = false;
            ShowIcon = false;
            BackColor = Color.White;

            if (!DwmIsCompositionEnabled() || DesignMode)
                Controls.Add(NoDWMLabel);

            Controls.Add(WizardIconPictureBox);
            Controls.Add(NavigationButton);

            NoDWMLabel.BringToFront();
            WizardIconPictureBox.BringToFront();
            NavigationButton.BringToFront();
            NavButtonStatusChanged();

            #endregion
        }

        #endregion

        #region Public Properties

        ///<summary>
        /// Gets a value representing whether or not Windows Aero is supported.
        ///</summary>
        /// <returns>True if Windows Aero is supported, otherwise, false</returns>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Gets a value representing whether or not Windows Aero is supported.")]
        public bool isAeroEnabled
        {
            get { return Environment.OSVersion.Version.Major > 5 && DwmIsCompositionEnabled() && !DesignMode; }
        }

        /// <summary>
        /// Gets or sets a value that determines whether or not the previous button is enabled
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Gets a value that determines whether or not the previous button is enabled")]
        public bool EnablePreviousButton
        {
            get { return enablePreviousButton; }
            set
            {
                enablePreviousButton = value;
                if (NavigationButton != null) NavButtonStatusChanged();
            }
        }

        /// <summary>
        /// Gets or sets the icon being displayed on the form
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Gets or sets the icon being displayed on the form")]
        public Image WizardIcon
        {
            get { return WizardIconPictureBox.Image; }
            set { if (WizardIconPictureBox != null) WizardIconPictureBox.Image = value; }
        }

        #endregion

        #region Protected Methods

        public override string Text
        {
            get { return base.Text; }
            set
            {
                if (WindowTitle != null) WindowTitle.Text = spaces + value;
                base.Text = value;
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_DWMCOMPOSITIONCHANGED || m.Msg == WM_DWMNCRENDERINGCHANGED)
            {
                if (DesktopCompositionChanged != null)
                {
                    var args = new CompositionChangedEventArgs(DwmIsCompositionEnabled());
                    DesktopCompositionChanged.Invoke(this, args);
                }
            }

            base.WndProc(ref m);
        }

        #endregion

        #region Nested type: MARGINS

        ///<summary>
        /// MARGINS struct
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct MARGINS
        {
            ///<summary>
            /// Left
            ///</summary>
            public int Left;

            /// <summary>
            /// Right
            /// </summary>
            public int Right;

            /// <summary>
            /// Top
            /// </summary>
            public int Top;

            /// <summary>
            /// Bottom
            /// </summary>
            public int Bottom;
        }

        #endregion

        #region Nested type: WTA_OPTIONS

        ///<summary>
        /// Defines options that are used to set window visual style attributes.
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct WTA_OPTIONS
        {
            /// <summary>
            /// Flags
            /// </summary>
            public uint Flags;

            /// <summary>
            /// Mask
            /// </summary>
            public uint Mask;
        }

        #endregion

        #region Private Methods

        private void InvokeNextEvent()
        {
            if (Next != null) Next.Invoke(this, new EventArgs());
        }

        private void InvokePreviousEvent()
        {
            if (Previous != null) Previous.Invoke(this, new EventArgs());
        }

        private void InvokeCancelRequestEvent()
        {
            if (CancelRequest != null) CancelRequest.Invoke(this, new EventArgs());
        }

        private void NextButton_Click(object sender, EventArgs e)
        {
            InvokeNextEvent();
        }

        private void CancelRequestButton_Click(object sender, EventArgs e)
        {
            InvokeCancelRequestEvent();
        }

        private void JPAeroForm_Resize(object sender, EventArgs e)
        {
            if (CancelRequestButton != null) CancelRequestButton.Location = new Point(Width - 94, 9);
            if (NextButton != null) NextButton.Location = new Point(Width - 169, 9);
        }

        private void NavigationButton_Click(object sender, EventArgs e)
        {
            if ((NAV_BACKBUTTONSTATES)NavigationButton.Tag != NAV_BACKBUTTONSTATES.NAV_BB_DISABLED)
            {
                InvokePreviousEvent();
            }
        }

        private void NavButtonStatusChanged()
        {
            if (EnablePreviousButton)
            {
                NavigationButton.Tag = NAV_BACKBUTTONSTATES.NAV_BB_NORMAL;
                NavigationButton.Image = Resources.normal;
            }
            else
            {
                NavigationButton.Tag = NAV_BACKBUTTONSTATES.NAV_BB_DISABLED;
                NavigationButton.Image = Resources.disabled2;
            }
        }

        private void NavigationButton_MouseUp(object sender, MouseEventArgs e)
        {
            NavigationButton.Image = (NAV_BACKBUTTONSTATES)NavigationButton.Tag == NAV_BACKBUTTONSTATES.NAV_BB_NORMAL ? Resources.hot : Resources.disabled2;
        }

        private void NavigationButton_MouseEnter(object sender, EventArgs e)
        {
            NavigationButton.Image = (NAV_BACKBUTTONSTATES)NavigationButton.Tag == NAV_BACKBUTTONSTATES.NAV_BB_NORMAL ? Resources.hot : Resources.disabled2;
        }

        private void NavigationButton_MouseDown(object sender, MouseEventArgs e)
        {
            NavigationButton.Image = (NAV_BACKBUTTONSTATES)NavigationButton.Tag == NAV_BACKBUTTONSTATES.NAV_BB_NORMAL ? Resources.pressed5 : Resources.disabled2;
        }

        private void NavigationButton_MouseLeave(object sender, EventArgs e)
        {
            NavigationButton.Image = (NAV_BACKBUTTONSTATES)NavigationButton.Tag == NAV_BACKBUTTONSTATES.NAV_BB_NORMAL ? Resources.normal : Resources.disabled2;
        }

        #endregion

        private enum NAV_BACKBUTTONSTATES
        {
            NAV_BB_NORMAL = 1,
            NAV_BB_HOT = 2,
            NAV_BB_PRESSED = 3,
            NAV_BB_DISABLED = 4,
        };
    }

    #region EventArgs

    /// <summary>
    /// Raised when the DWM composition state is changed
    /// </summary>
    public class CompositionChangedEventArgs : EventArgs
    {
        #region Private Variables

        private readonly bool availability;

        #endregion

        #region Constructor

        ///<summary>
        /// Constructs the CompositionChangedEventArgs class
        ///</summary>
        ///<param name="Availability">Availability of Windows Aero styles</param>
        public CompositionChangedEventArgs(bool Availability)
        {
            availability = Availability;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the new DWM state
        /// </summary>
        public bool IsGlassAvailable
        {
            get { return availability; }
        }

        #endregion
    }

    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)



Comments and Discussions