Click here to Skip to main content
15,897,371 members
Articles / Desktop Programming / Windows Forms

Windows Ribbon for WinForms, Part 3 - First WinForms Ribbon Application

Rate me:
Please Sign up or sign in to vote.
4.29/5 (18 votes)
4 Mar 2010Ms-PL4 min read 53.1K   3.8K   32  
In this article, I'll present how to create an empty WinForms application with Windows 7 ribbon support.
//*****************************************************************************
//
//  File:       Ribbon.cs
//
//  Contents:   Class which is used as a façade for the Windows Ribbon 
//              Framework. In charge of initialization and communication with 
//              the Windows Ribbon Framework.
//
//*****************************************************************************

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using RibbonLib.Interop;

namespace RibbonLib
{
    /// <summary>
    /// Main class for using the windows ribbon in a .NET application
    /// </summary>
    public class Ribbon : IUICommandHandler
    {
        private IUIImageFromBitmap _imageFromBitmap;
        private RibbonUIApplication _application;
        private Dictionary<uint, IRibbonControl> _mapRibbonControls = new Dictionary<uint, IRibbonControl>();
        private IntPtr _loadedDllHandle = IntPtr.Zero;

        private const string DefaultResourceName = "APPLICATION_RIBBON";

        /// <summary>
        /// Check if ribbon framework has been initialized
        /// </summary>
        public bool Initalized
        {
            get
            {
                return (Framework != null);
            }
        }

        /// <summary>
        /// Get ribbon framework object
        /// </summary>
        public IUIFramework Framework { get; private set; }


        /// <summary>
        /// Initalize ribbon framework
        /// </summary>
        /// <param name="form">Form where ribbon should reside</param>
        public void InitFramework(IRibbonForm form)
        {
            string defaultRibbonDllName = GenerateDefaultRibbonDllName();

            // if ribbon dll exists, use it
            if (File.Exists(defaultRibbonDllName))
            {
                // load ribbon from ribbon dll resource
                InitFramework(form, DefaultResourceName, defaultRibbonDllName);
            }
            else 
            {
                // load ribbon from executable naive resource
                InitFramework(form, DefaultResourceName, Assembly.GetEntryAssembly().GetModules()[0]);
            }
        }

        /// <summary>
        /// Initalize ribbon framework
        /// </summary>
        /// <param name="form">Form where ribbon should reside</param>
        /// <param name="resourceName">Identifier of the ribbon resource</param>
        /// <param name="resourceModule">Module where to find ribbon resource</param>
        public void InitFramework(IRibbonForm form, string resourceName, Module resourceModule)
        {
            // get main module HINSTANCE
            IntPtr hInstance = Marshal.GetHINSTANCE(resourceModule);

            InitFramework(form, resourceName, hInstance);
        }

        /// <summary>
        /// Initalize ribbon framework
        /// </summary>
        /// <param name="form">Form where ribbon should reside</param>
        /// <param name="resourceName">Identifier of the ribbon resource</param>
        /// <param name="ribbonDllName">Dll name where to find ribbon resource</param>
        public void InitFramework(IRibbonForm form, string resourceName, string ribbonDllName)
        {
            // dynamically load ribbon library
            _loadedDllHandle = NativeMethods.LoadLibraryEx(ribbonDllName, IntPtr.Zero,
                                                            NativeMethods.DONT_RESOLVE_DLL_REFERENCES |
                                                            NativeMethods.LOAD_IGNORE_CODE_AUTHZ_LEVEL |
                                                            NativeMethods.LOAD_LIBRARY_AS_DATAFILE |
                                                            NativeMethods.LOAD_LIBRARY_AS_IMAGE_RESOURCE);

            InitFramework(form, resourceName, _loadedDllHandle);
        }

        /// <summary>
        /// Initalize ribbon framework
        /// </summary>
        /// <param name="form">Form where ribbon should reside</param>
        /// <param name="resourceName">Identifier of the ribbon resource</param>
        /// <param name="hInstance">Pointer to HINSTANCE of module where we can find ribbon resource</param>
        public void InitFramework(IRibbonForm form, string resourceName, IntPtr hInstance)
        {
            // create ribbon framework object
            Framework = CreateRibbonFramework();
            _imageFromBitmap = CreateImageFromBitmapFactory();

            // create ribbon application object
            _application = new RibbonUIApplication(this, form);

            // init ribbon framework
            HRESULT hr = Framework.Initialize(form.WindowHandle, _application);
            if (NativeMethods.Failed(hr))
            {
                Marshal.ThrowExceptionForHR((int)hr);
            }

            // load ribbon ui
            hr = Framework.LoadUI(hInstance, resourceName);
            if (NativeMethods.Failed(hr))
            {
                Marshal.ThrowExceptionForHR((int)hr);
            }
        }
        
        /// <summary>
        /// Destroy ribbon framework
        /// </summary>
        public void DestroyFramework()
        {
            if (Initalized)
            {
                // destroy ribbon framework
                Framework.Destroy();
                Marshal.ReleaseComObject(Framework);

                // remove reference to framework object
                Framework = null;
            }

            if (_loadedDllHandle != IntPtr.Zero)
            {
                // free dynamic library
                NativeMethods.FreeLibrary(_loadedDllHandle);
                _loadedDllHandle = IntPtr.Zero;
            }

            if (_imageFromBitmap != null)
            {
                // remove reference to imageFromBitmap object
                _imageFromBitmap = null;
            }

            if (_application != null)
            {
                // remove reference to application object
                _application = null;
            }

            // remove references to ribbon controls
            _mapRibbonControls.Clear();
        }

        /// <summary>
        /// Change ribbon background, highlight and text colors
        /// </summary>
        /// <param name="background">new background color</param>
        /// <param name="highlight">new highlight color</param>
        /// <param name="text">new text color</param>
        public void SetColors(Color background, Color highlight, Color text)
        {
            if (!Initalized)
            {
                return;
            }

            // convert colors to proper color format
            uint backgroundColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(background)));
            uint highlightColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(highlight)));
            uint textColor = ColorHelper.HSB2Uint(ColorHelper.HSL2HSB(ColorHelper.RGB2HSL(text)));
            
            IPropertyStore propertyStore = (IPropertyStore)Framework;

            PropVariant backgroundColorProp = PropVariant.FromObject(backgroundColor);
            PropVariant highlightColorProp = PropVariant.FromObject(highlightColor);
            PropVariant textColorProp = PropVariant.FromObject(textColor);

            // set ribbon colors
            propertyStore.SetValue(ref RibbonProperties.GlobalBackgroundColor, ref backgroundColorProp);
            propertyStore.SetValue(ref RibbonProperties.GlobalHighlightColor, ref highlightColorProp);
            propertyStore.SetValue(ref RibbonProperties.GlobalTextColor, ref textColorProp);

            propertyStore.Commit();
        }

        /// <summary>
        /// Wraps a bitmap object with IUIImage interface
        /// </summary>
        /// <param name="bitmap">bitmap object to wrap</param>
        /// <returns>IUIImage wrapper</returns>
        public IUIImage ConvertToUIImage(Bitmap bitmap)
        {
            if (_imageFromBitmap == null)
            {
                return null;
            }

            IUIImage uiImage;
            _imageFromBitmap.CreateImage(bitmap.GetHbitmap(), Ownership.Transfer, out uiImage);

            return uiImage;
        }

        /// <summary>
        /// Set current application modes
        /// </summary>
        /// <param name="modesArray">array of modes to set</param>
        /// <remarks>Unlisted modes will be unset</remarks>
        public void SetModes(params byte[] modesArray)
        {
            // check that ribbon is initialized
            if (!Initalized)
            {
                return;
            }

            // calculate compact modes value
            int compactModes = 0;
            for (int i = 0; i < modesArray.Length; ++i)
            {
                if (modesArray[i] >= 32)
                {
                    throw new ArgumentException("Modes should range between 0 to 31.");
                }

                compactModes |= (1 << modesArray[i]);
            }

            // set modes
            Framework.SetModes(compactModes);        
        }

        /// <summary>
        /// Shows a predefined context popup in a specific location
        /// </summary>
        /// <param name="contextPopupID">commandId for the context popup</param>
        /// <param name="x">X in screen coordinates</param>
        /// <param name="y">Y in screen coordinates</param>
        public void ShowContextPopup(uint contextPopupID, int x, int y)
        {
            // check that ribbon is initialized
            if (!Initalized)
            {
                return;
            }

            object contextualUIObject;
            Guid contextualUIGuid = new Guid(RibbonIIDGuid.IUIContextualUI);
            HRESULT hr = Framework.GetView(contextPopupID, ref contextualUIGuid, out contextualUIObject);
            if (NativeMethods.Succeeded(hr))
            {
                IUIContextualUI contextualUI = contextualUIObject as IUIContextualUI;
                contextualUI.ShowAtLocation(x, y);
                Marshal.ReleaseComObject(contextualUI);
            }
            else
            {
                Marshal.ThrowExceptionForHR((int)hr);
            }
        }

        /// <summary>
        /// Specifies whether the ribbon is in a collapsed or expanded state
        /// </summary>
        public bool Minimized
        {
            get
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return false;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propMinimized;
                HRESULT hr = propertyStore.GetValue(ref RibbonProperties.Minimized, out propMinimized);
                return (bool)propMinimized.Value;
            }
            set
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propMinimized = PropVariant.FromObject(value);
                HRESULT hr = propertyStore.SetValue(ref RibbonProperties.Minimized, ref propMinimized);
                hr = propertyStore.Commit();
            }
        }

        /// <summary>
        /// Specifies whether the ribbon user interface (UI) is in a visible or hidden state
        /// </summary>
        public bool Viewable
        {
            get
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return false;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propViewable;
                HRESULT hr = propertyStore.GetValue(ref RibbonProperties.Viewable, out propViewable);
                return (bool)propViewable.Value;
            }
            set
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propViewable = PropVariant.FromObject(value);
                HRESULT hr = propertyStore.SetValue(ref RibbonProperties.Viewable, ref propViewable);
                hr = propertyStore.Commit();
            }
        }

        /// <summary>
        /// Specifies whether the quick access toolbar is docked at the top or at the bottom
        /// </summary>
        public ControlDock QuickAccessToolbarDock
        {
            get
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return ControlDock.Top;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propQuickAccessToolbarDock;
                HRESULT hr = propertyStore.GetValue(ref RibbonProperties.QuickAccessToolbarDock, out propQuickAccessToolbarDock);
                return (ControlDock)(uint)propQuickAccessToolbarDock.Value;
            }
            set
            {
                // check that ribbon is initialized
                if (!Initalized)
                {
                    return;
                }

                IPropertyStore propertyStore = _application.UIRibbon as IPropertyStore;
                PropVariant propQuickAccessToolbarDock = PropVariant.FromObject((uint)value);
                HRESULT hr = propertyStore.SetValue(ref RibbonProperties.QuickAccessToolbarDock, ref propQuickAccessToolbarDock);
                hr = propertyStore.Commit();
            }
        }

        public void SaveSettingsToStream(Stream stream)
        {
            if (!Initalized)
            {
                return;
            }

            StreamAdapter streamAdapter = new StreamAdapter(stream);
            HRESULT hr = _application.UIRibbon.SaveSettingsToStream(streamAdapter);
        }

        public void LoadSettingsFromStream(Stream stream)
        {
            if (!Initalized)
            {
                return;
            }

            StreamAdapter streamAdapter = new StreamAdapter(stream);
            HRESULT hr = _application.UIRibbon.LoadSettingsFromStream(streamAdapter);
        }

        /// <summary>
        /// Create ribbon framework object
        /// </summary>
        /// <returns>ribbon framework object</returns>
        private static IUIFramework CreateRibbonFramework()
        {
            try
            {
                return new UIRibbonFramework() as IUIFramework;
            }
            catch (COMException exception)
            {
                throw new PlatformNotSupportedException("The ribbon framework couldn't be found on this system.", exception);
            }
        }

        /// <summary>
        /// Create image-from-bitmap factory object
        /// </summary>
        /// <returns>image-from-bitmap factory object</returns>
        private static IUIImageFromBitmap CreateImageFromBitmapFactory()
        {
            return new UIRibbonImageFromBitmapFactory() as IUIImageFromBitmap;
        }

        /// <summary>
        /// Generates a default ribbon dll name
        /// </summary>
        /// <returns>name of the dll</returns>
        private string GenerateDefaultRibbonDllName()
        {
            return Path.ChangeExtension(new Uri(Assembly.GetEntryAssembly().CodeBase).LocalPath, ".ribbon.dll");
        }
        
        /// <summary>
        /// Adds a ribbon control to the internal map
        /// </summary>
        /// <param name="ribbonControl">ribbon control to add</param>
        internal void AddRibbonControl(IRibbonControl ribbonControl)
        {
            _mapRibbonControls.Add(ribbonControl.CommandID, ribbonControl);
        }
        
        #region Implementation of IUICommandHandler

        /// <summary>
        /// Implementation of IUICommandHandler.Execute
        /// Responds to execute events on Commands bound to the Command handler
        /// </summary>
        /// <param name="commandID">the command that has been executed</param>
        /// <param name="verb">the mode of execution</param>
        /// <param name="key">the property that has changed</param>
        /// <param name="currentValue">the new value of the property that has changed</param>
        /// <param name="commandExecutionProperties">additional data for this execution</param>
        /// <returns>Returns S_OK if successful, or an error value otherwise</returns>
        /// <remarks>This method is used internally by the Ribbon class and should not be called by the user.</remarks>
        public virtual HRESULT Execute(uint commandID, ExecutionVerb verb, PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
        {
#if DEBUG
            Debug.WriteLine(string.Format("Execute verb: {0} for command {1}", verb, commandID));
#endif
            
            if (_mapRibbonControls.ContainsKey(commandID))
            {
                return _mapRibbonControls[commandID].Execute(verb, key, currentValue, commandExecutionProperties);
            }

            return HRESULT.S_OK;
        }

        /// <summary>
        /// Implementation of IUICommandHandler.UpdateProperty
        /// Responds to property update requests from the Windows Ribbon (Ribbon) framework. 
        /// </summary>
        /// <param name="commandID">The ID for the Command, which is specified in the Markup resource file</param>
        /// <param name="key">The Property Key to update</param>
        /// <param name="currentValue">A pointer to the current value for key. This parameter can be NULL</param>
        /// <param name="newValue">When this method returns, contains a pointer to the new value for key</param>
        /// <returns>Returns S_OK if successful, or an error value otherwise</returns>
        /// <remarks>This method is used internally by the Ribbon class and should not be called by the user.</remarks>
        public virtual HRESULT UpdateProperty(uint commandID, ref PropertyKey key, PropVariantRef currentValue, ref PropVariant newValue)
        {
#if DEBUG
            Debug.WriteLine(string.Format("UpdateProperty key: {0} for command {1}", RibbonProperties.GetPropertyKeyName(ref key), commandID));
#endif

            if (_mapRibbonControls.ContainsKey(commandID))
            {
                return _mapRibbonControls[commandID].UpdateProperty(ref key, currentValue, ref newValue);
            }

            return HRESULT.S_OK;
        }

        #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 Microsoft Public License (Ms-PL)


Written By
Software Developer (Senior) Verint
Israel Israel
Arik Poznanski is a senior software developer at Verint. He completed two B.Sc. degrees in Mathematics & Computer Science, summa cum laude, from the Technion in Israel.

Arik has extensive knowledge and experience in many Microsoft technologies, including .NET with C#, WPF, Silverlight, WinForms, Interop, COM/ATL programming, C++ Win32 programming and reverse engineering (assembly, IL).

Comments and Discussions