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:
<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;
}
}
}
}