Skip to main content

How to create a RibbonControl

  • 10 minutes to read

This example shows how to create a RibbonControl in XAML. The control contains a Default Page Category, displaying three Ribbon pages (File, Edit and Format). In addition, a custom page category (“Selection”) is defined, which is initially hidden, and made visible on selecting text in a text editor (see the complete sample).

The following image shows the result:

RibbonControl_Ex

View Example

<dx:ThemedWindow x:Class="RibbonControl_Ex.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="379" Width="643"
        xmlns:local="clr-namespace:RibbonControl_Ex"
        xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
        xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
        xmlns:dxr="http://schemas.devexpress.com/winfx/2008/xaml/ribbon"
        xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/core"
        xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
        Icon="{dxc:DXImage Image=Home_16x16.png}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <dxr:RibbonControl x:Name="RibbonControl" Grid.Row="0" 
                           ApplicationButtonSmallIcon="{dxc:DXImage Image=Home_16x16.png}" 
                           ApplicationButtonLargeIcon="{dxc:DXImage Image=Home_32x32.png}" 
                           ApplicationButtonText="File" 
                           PageCategoryAlignment="Right"
                           RibbonStyle="Office2010">
            <!--region #AppMenu-->
            <dxr:RibbonControl.ApplicationMenu>
                <dxr:ApplicationMenu RightPaneWidth="280" ShowRightPane="True">
                    <dxr:ApplicationMenu.ItemLinks>
                        <dxb:BarButtonItemLink BarItemName="bNew"/>
                        <dxb:BarButtonItemLink BarItemName="bOpen"/>
                        <dxb:BarItemLinkSeparator/>
                        <dxb:BarSplitButtonItemLink BarItemName="sbSave"/>
                        <dxb:BarButtonItemLink BarItemName="bPrint"/>
                        <dxb:BarItemLinkSeparator/>
                        <dxb:BarButtonItemLink BarItemName="bAbout"/>
                    </dxr:ApplicationMenu.ItemLinks>
                    <dxr:ApplicationMenu.RightPane>
                        <Border Background="White" BorderThickness="1,0,0,0" BorderBrush="LightGray">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Border BorderThickness="0,0,0,1" BorderBrush="LightGray" Margin="7,5,5,0">
                                    <Label FontWeight="Bold">Recent Documents:</Label>
                                </Border>
                                <ListBox Grid.Row="1" BorderThickness="0" Margin="2,0,0,0" >
                                    <ListBox.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal" Margin="0,2,0,0">
                                                <Border BorderThickness="0,0,0,1" BorderBrush="Black">
                                                    <TextBlock Text="{Binding Number}"/>
                                                </Border>
                                                <TextBlock Text="{Binding FileName}" Margin="7,0,0,0"/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ListBox.ItemTemplate>
                                    <ListBox.Items>
                                        <local:RecentItem  Number="1" FileName="Document4.rtf"/>
                                        <local:RecentItem  Number="2" FileName="Document3.rtf"/>
                                        <local:RecentItem  Number="3" FileName="Document2.rtf"/>
                                        <local:RecentItem  Number="4" FileName="Document1.rtf"/>
                                    </ListBox.Items>
                                </ListBox>
                            </Grid>
                        </Border>
                    </dxr:ApplicationMenu.RightPane>
                    <dxr:ApplicationMenu.BottomPane>
                        <StackPanel Orientation="Horizontal">
                            <Button Click="OptionsButton_Click" Content="Options" Width="100" Margin="0,0,10,0" />
                            <Button Click="ExitButton_Click" Content="Exit" Width="100" />
                        </StackPanel>
                    </dxr:ApplicationMenu.BottomPane>
                </dxr:ApplicationMenu>
            </dxr:RibbonControl.ApplicationMenu>
            <!--endregion #AppMenu-->

            <!--region #PageHeaderItemLinks-->
            <dxr:RibbonControl.PageHeaderItems>
                <dxb:BarEditItem x:Name="eRibbonStyle" Content="Ribbon Style:" 
                    EditWidth="100" 
                    ClosePopupOnChangingEditValue="True" 
                    EditValue="{Binding RibbonStyle, ElementName=RibbonControl}">
                    <dxb:BarEditItem.EditSettings>
                        <dxe:ComboBoxEditSettings IsTextEditable="False" PopupMaxHeight="250" 
                                                  ItemsSource="{dxe:EnumItemsSource EnumType={x:Type dxr:RibbonStyle}}"/>
                    </dxb:BarEditItem.EditSettings>
                </dxb:BarEditItem>
                <dxb:BarButtonItem Name="bAbout" Content="About" 
                                   Glyph="{dxc:DXImage Image=Info_16x16.png}" 
                                   LargeGlyph="{dxc:DXImage Image=Info_32x32.png}" 
                                   ItemClick="bAbout_ItemClick" />
            </dxr:RibbonControl.PageHeaderItems>
            <!--endregion #PageHeaderItemLinks-->

            <!--region #ToolbarItemLinks-->
            <dxr:RibbonControl.ToolbarItemLinks>
                <dxb:BarButtonItemLink BarItemName="bOpen"/>
                <dxb:BarButtonItemLink BarItemName="bSave"/>
            </dxr:RibbonControl.ToolbarItemLinks>
            <!--endregion #ToolbarItemLinks-->

            <!--region #DefaultPageCategory-->
            <dxr:RibbonDefaultPageCategory>
                <dxr:RibbonPage Caption="Home">
                    <dxr:RibbonPageGroup Name="pgFile" Caption="File" 
                                         ShowCaptionButton="True"
                                         CaptionButtonClick="groupFile_CaptionButtonClick">
                        <dxb:BarButtonItem Name="bNew" Content="New" 
                               Glyph="{dxc:DXImage Image=New_16x16.png}" 
                               LargeGlyph="{dxc:DXImage Image=New_32x32.png}"  
                               Description="Creates a new document."
                               Hint="Creates a blank document."
                               RibbonStyle="Large"/>

                        <dxb:BarButtonItem Name="bOpen" Content="Open" 
                               Glyph="{dxc:DXImage Image=Open_16x16.png}" 
                               LargeGlyph="{dxc:DXImage Image=Open_32x32.png}" 
                               Description="Opens a file."
                               Hint="Opens a file."
                               RibbonStyle="SmallWithText"/>

                        <dxb:BarButtonItem Name="bClose" Content="Close" 
                               Glyph="{dxc:DXImage Image=Close_16x16.png}" 
                               LargeGlyph="{dxc:DXImage Image=Close_32x32.png}"
                               Hint="Closes the current document"
                               RibbonStyle="SmallWithText"/>

                        <dxb:BarButtonItem Name="bPrint" Content="Print" 
                               Glyph="{dxc:DXImage Image=Print_16x16.png}" 
                               LargeGlyph="{dxc:DXImage Image=Print_32x32.png}"  
                               Description="Prints the document."
                               Hint="Prints the document." 
                               RibbonStyle="SmallWithText"/>

                        <dxb:BarItemLinkSeparator/>

                        <dxb:BarSplitButtonItem Name="sbSave" Content="Save" 
                                    Glyph="{dxc:DXImage Image=Save_16x16.png}" 
                                    LargeGlyph="{dxc:DXImage Image=Save_32x32.png}" 
                                    RibbonStyle="Large">
                            <dxb:BarSplitButtonItem.PopupControl >
                                <dxb:PopupMenu>
                                    <dxb:BarButtonItem Name="bSave" Content="Save" 
                                        Glyph="{dxc:DXImage Image=Save_16x16.png}" 
                                        LargeGlyph="{dxc:DXImage Image=Save_32x32.png}"  
                                        Description="Saves the document."
                                        Hint="Saves the document."/>
                                    <dxb:BarButtonItem Name="bSaveAs" Content="Save As..." 
                                        Glyph="{dxc:DXImage Image=SaveDialog_16x16.png}" 
                                        LargeGlyph="{dxc:DXImage Image=SaveDialog_32x32.png}" 
                                        Description="Save Document As..."
                                        Hint="Save Document As..."/>
                                </dxb:PopupMenu>
                            </dxb:BarSplitButtonItem.PopupControl>
                        </dxb:BarSplitButtonItem>
                    </dxr:RibbonPageGroup>

                    <dxr:RibbonPageGroup Caption="Edit" ShowCaptionButton="True" CaptionButtonClick="groupEdit_CaptionButtonClick">
                        <dxb:BarButtonItem Name="bPaste" Content="Paste" 
                               Glyph="{dxc:DXImage Image=Paste_16x16.png}" 
                               LargeGlyph="{dxc:DXImage Image=Paste_32x32.png}" RibbonStyle="Large"/>
                        <dxb:BarButtonItem Name="bCut" Content="Cut" 
                               Glyph="{dxc:DXImage Image=Cut_16x16.png}"  RibbonStyle="SmallWithText"/>
                        <dxb:BarButtonItem Name="bCopy" Content="Copy" 
                               Glyph="{dxc:DXImage Image=Copy_16x16.png}"  RibbonStyle="SmallWithText"/>
                        <dxb:BarButtonItem Name="bClear" Content="Clear" 
                               Glyph="{dxc:DXImage Image=Delete_16x16.png}"  RibbonStyle="SmallWithText"/>
                    </dxr:RibbonPageGroup>

                    <dxr:RibbonPageGroup Caption="Format" ShowCaptionButton="False">
                        <!--region #BarButtonGroup-->
                        <dxr:BarButtonGroup Name="bgFontShape" RibbonStyle="SmallWithoutText">
                            <dxb:BarCheckItem Name="bBold" Content="Bold" 
                              Glyph="{dxc:DXImage Image=Bold_16x16.png}" />
                            <dxb:BarCheckItem Name="bItalic" Content="Italic" 
                              Glyph="{dxc:DXImage Image=Italic_16x16.png}" />
                            <dxb:BarCheckItem Name="bUnderline" Content="Underline" 
                              Glyph="{dxc:DXImage Image=Underline_16x16.png}" />
                        </dxr:BarButtonGroup>
                        <!--endregion #BarButtonGroup-->
                    </dxr:RibbonPageGroup>
                </dxr:RibbonPage>
            </dxr:RibbonDefaultPageCategory>
            <!--endregion #DefaultPageCategory-->

            <!--region #CustomPageCategory-->
            <dxr:RibbonPageCategory x:Name="categorySelection" 
                                    Caption="Selection" 
                                    Color="Yellow" 
                                    IsVisible="False">
                <dxr:RibbonPage Caption="Gallery Page">
                    <dxr:RibbonPageGroup Caption="Font" ShowCaptionButton="False">
                        <!--region #RibbonGalleryBarItem-->
                        <dxr:RibbonGalleryBarItem Name="gFont" Glyph="{dxc:DXImage Image=ChangeFontStyle_16x16.png}" Content="Font">
                            <dxr:RibbonGalleryBarItem.Links>
                                <dxb:BarEditItemLink BarItemName="eFontSize" RibbonStyle="SmallWithText"/>
                            </dxr:RibbonGalleryBarItem.Links>
                            <dxr:RibbonGalleryBarItem.Gallery>
                                <dxb:Gallery MinColCount="1" ColCount="5" 
                                    ItemCheckMode="Single" 
                                    IsGroupCaptionVisible="False" 
                                    IsItemCaptionVisible="False"
                                    IsItemDescriptionVisible="False" 
                                    ItemChecked="FontFamilyGallery_ItemChecked" 
                                    ItemCaptionVerticalAlignment="Center">
                                    <dxb:Gallery.Groups>
                                        <dxb:GalleryItemGroup Name="FontFamilyGalleryGroup" />
                                    </dxb:Gallery.Groups>
                                </dxb:Gallery>
                            </dxr:RibbonGalleryBarItem.Gallery>

                            <dxr:RibbonGalleryBarItem.DropDownGallery>
                                <dxb:Gallery MinColCount="1" ColCount="1" 
                                    RowCount="5" 
                                    ItemCheckMode="Single" 
                                    IsGroupCaptionVisible="False"
                                    AllowFilter="False"
                                    IsItemGlyphVisible="True" 
                                    IsItemDescriptionVisible="False" 
                                    ItemContentHorizontalAlignment="Stretch"
                                    ItemContentVerticalAlignment="Center" 
                                    ItemChecked="FontFamilyGallery_ItemChecked"
                                    SizeMode="Vertical">
                                    <dxb:Gallery.Groups>
                                        <dxb:GalleryItemGroup Name="FontFamilyDropDownGalleryGroup" />
                                    </dxb:Gallery.Groups>
                                </dxb:Gallery>
                            </dxr:RibbonGalleryBarItem.DropDownGallery>
                        </dxr:RibbonGalleryBarItem>
                        <!--endregion #RibbonGalleryBarItem-->

                        <dxb:BarEditItem Name="eFontSize" RibbonStyle="SmallWithoutText" EditWidth="90"
                             Content="Font Size:" 
                             EditValueChanged="eFontSize_EditValueChanged">
                            <dxb:BarEditItem.EditSettings>
                                <dxe:ComboBoxEditSettings PopupMaxHeight="250" IsTextEditable="False"/>
                            </dxb:BarEditItem.EditSettings>
                        </dxb:BarEditItem>

                    </dxr:RibbonPageGroup>
                </dxr:RibbonPage>
            </dxr:RibbonPageCategory>
            <!--endregion #CustomPageCategory-->
        </dxr:RibbonControl>

        <!--region #RibbonStatusBarControl-->
        <dxr:RibbonStatusBarControl Grid.Row="2" Name="StatusBar" IsSizeGripVisible="True" Grid.ColumnSpan="2">
            <dxr:RibbonStatusBarControl.RightItems>
                <dxb:BarStaticItem Name="bFileName" ItemMinWidth="150" AutoSizeMode="Fill" Content="Binding"/>
            </dxr:RibbonStatusBarControl.RightItems>
            <dxr:RibbonStatusBarControl.LeftItems>
                <dxb:BarStaticItem Name="bPosInfo" ItemMinWidth="150"/>
            </dxr:RibbonStatusBarControl.LeftItems>
        </dxr:RibbonStatusBarControl>
        <!--endregion #RibbonStatusBarControl-->

        <RichTextBox x:Name="textEditor" Grid.Row="1" BorderThickness="0" SelectionChanged="textEditor_SelectionChanged" Grid.ColumnSpan="2"/>

    </Grid>
</dx:ThemedWindow>
using DevExpress.Xpf.Bars;
using DevExpress.Xpf.Core;
using DevExpress.Xpf.Editors.Settings;
using DevExpress.Xpf.Ribbon;
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace RibbonControl_Ex {
    public partial class MainWindow : ThemedWindow {

        public MainWindow() {
            InitializeComponent();
            bFileName.Content = "Document 1";
            ((ComboBoxEditSettings)eFontSize.EditSettings).ItemsSource = (new FontSizes()).Items;
            InitializeFontFamilyGallery();
        }

        void InitializeFontFamilyGallery() {
            foreach (FontFamily fontFamily in (new DecimatedFontFamilies()).Items) {
                ImageSource src = CreateImage(fontFamily);
                FontFamilyGalleryGroup.Items.Add(CreateItem(fontFamily, src));
                FontFamilyDropDownGalleryGroup.Items.Add(CreateItem(fontFamily, src));
            }
        }

        FormattedText fmtText = null;
        FormattedText createFormattedText(FontFamily fontFamily) {
            return new FormattedText("Aa", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), 18, Brushes.Black, null, TextFormattingMode.Ideal);
        }

        ImageSource CreateImage(FontFamily fontFamily) {
            const double DimensionSize = 32;
            const double HalfDimensionSize = DimensionSize / 2d;
            DrawingVisual v = new DrawingVisual();
            DrawingContext c = v.RenderOpen();
            c.DrawRectangle(Brushes.White, null, new Rect(0, 0, DimensionSize, DimensionSize));
            if (fmtText == null)
                fmtText = createFormattedText(fontFamily);
            fmtText.SetFontFamily(fontFamily);
            fmtText.TextAlignment = TextAlignment.Center;
            double verticalOffset = (DimensionSize - fmtText.Baseline) / 2d;
            c.DrawText(fmtText, new Point(HalfDimensionSize, verticalOffset));
            c.Close();

            RenderTargetBitmap rtb = new RenderTargetBitmap((int)DimensionSize, (int)DimensionSize, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(v);
            return rtb;
        }

        GalleryItem CreateItem(FontFamily fontFamily, ImageSource image) {
            GalleryItem item = new GalleryItem();
            item.Glyph = image;
            item.Caption = fontFamily.ToString();
            item.Tag = fontFamily;
            return item;
        }

        void textEditor_SelectionChanged(object sender, RoutedEventArgs e) {
            ShowHideSelectionCategory();
            UpdateStatusCaretPosition();
            InvokeUpdateFormat();
        }

        bool isInvokePending = false;

        void InvokeUpdateFormat() {
            if (!isInvokePending) {
                Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(UpdateFormat));
                isInvokePending = true;
            }
            UpdateFormat();
        }

        protected void UpdateFormat() {
            object value = textEditor.Selection.GetPropertyValue(TextElement.FontSizeProperty);
            eFontSize.EditValue = (value == DependencyProperty.UnsetValue) ? null : value;
        }

        void ShowHideSelectionCategory() {
            if (textEditor == null)
                categorySelection.IsVisible = false;
            else
                categorySelection.IsVisible = !SelectedTextIsNullOrEmpty;
            if (categorySelection.IsVisible)
                RibbonControl.SelectedPage = categorySelection.Pages[0];
        }

        public bool SelectedTextIsNullOrEmpty { get { return string.IsNullOrEmpty(textEditor.Selection.Text); } }

        void UpdateStatusCaretPosition() {
            int line = 0;
            textEditor.CaretPosition.GetLineStartPosition(-100000, out line);
            int col = textEditor.CaretPosition.GetOffsetToPosition(textEditor.CaretPosition.GetLineStartPosition(0));
            bPosInfo.Content = "Line: " + (-line).ToString() + "  Position: " + (-col).ToString();
        }

        void FontFamilyGallery_ItemChecked(object sender, GalleryItemEventArgs e) {
            FontFamily newFontFamily = (FontFamily)e.Item.Tag;
            ApplyPropertyValueToSelectedText(TextElement.FontFamilyProperty, newFontFamily);
        }

        void eFontSize_EditValueChanged(object sender, RoutedEventArgs e) {
            ApplyPropertyValueToSelectedText(TextElement.FontSizeProperty, eFontSize.EditValue);
        }

        void ApplyPropertyValueToSelectedText(DependencyProperty formattingProperty, object value) {
            if (value == null) return;
            textEditor.Selection.ApplyPropertyValue(formattingProperty, value);
            //InvokeUpdateFormat();
            //InvokeFocusEdit();
        }

        void OptionsButton_Click(object sender, RoutedEventArgs e) {
            (RibbonControl.ApplicationMenu as ApplicationMenu).ClosePopup();
        }
        void ExitButton_Click(object sender, RoutedEventArgs e) {
            (RibbonControl.ApplicationMenu as ApplicationMenu).ClosePopup();
        }

        void groupEdit_CaptionButtonClick(object sender, EventArgs e) {
            MessageBox.Show("DevExpress Ribbon Control", "Edit Settings Dialog");
        }

        private void bAbout_ItemClick(object sender, ItemClickEventArgs e) {
            MessageBox.Show("DevExpress Ribbon Control", "About Window");
        }

        private void groupFile_CaptionButtonClick(object sender, RibbonCaptionButtonClickEventArgs e) {
            MessageBox.Show("DevExpress Ribbon Control", "File Settings Dialog");

        }
    }

    public class RecentItem {
        public int Number { get; set; }
        public string FileName { get; set; }
    }

    public class ButtonWithImageContent {
        public string ImageSource { get; set; }
        public object Content { get; set; }
    }

    public class FontSizes {
        public double[] Items {
            get {
                return new double[] {
                    3.0, 4.0, 5.0, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5,
                    10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 15.0,
                    16.0, 17.0, 18.0, 19.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0,
                    32.0, 34.0, 36.0, 38.0, 40.0, 44.0, 48.0, 52.0, 56.0, 60.0, 64.0, 68.0, 72.0, 76.0,
                    80.0, 88.0, 96.0, 104.0, 112.0, 120.0, 128.0, 136.0, 144.0
                };
            }
        }
    }

    public class DecimatedFontFamilies : FontFamilies {
        const int DecimationFactor = 5;
        public override ObservableCollection<FontFamily> Items {
            get {
                ObservableCollection<FontFamily> res = new ObservableCollection<FontFamily>();
                for (int i = 0; i < ItemsCore.Count; i++) {
                    if (i % DecimationFactor == 0)
                        res.Add(ItemsCore[i]);
                }
                return res;
            }
        }
    }

    public class FontFamilies {
        static ObservableCollection<FontFamily> items;
        protected static ObservableCollection<FontFamily> ItemsCore {
            get {
                if (items == null) {
                    items = new ObservableCollection<FontFamily>();
                    foreach (FontFamily fam in Fonts.SystemFontFamilies) {
                        if (!IsValidFamily(fam)) continue;
                        items.Add(fam);
                    }
                }
                return items;
            }
        }

        public static bool IsValidFamily(FontFamily fam) {
            foreach (Typeface f in fam.GetTypefaces()) {
                GlyphTypeface g = null;
                try {
                    if (f.TryGetGlyphTypeface(out g))
                        if (g.Symbol) return false;
                } catch (Exception) {
                    return false;
                }
            }
            return true;
        }

        public virtual ObservableCollection<FontFamily> Items {
            get {
                ObservableCollection<FontFamily> res = new ObservableCollection<FontFamily>();
                foreach (FontFamily fm in ItemsCore) {
                    res.Add(fm);
                }
                return res;
            }
        }
    }
}