Home » Programming » WPF » WPF Ribbon » WPF Ribbon (CTP) – Part 5 – Creating Custom Controls and Viewing Templates

WPF Ribbon (CTP) – Part 5 – Creating Custom Controls and Viewing Templates

Creating Custom Controls

Sometimes the default controls might not be enough for our needs. So what can we do then? Well, it’s simple: create our own controls. For example the CTP version does not have a color picker, but we can create our own.

Entire Tutorial:

Summary

  • Step 1: Creating a new application
  • Step 2: Implementing the IRibbonControl interface
  • Step 3: Changing the template of an existing RibbonControl – e.g. RibbonTextBox
    • Step 3a: Removing the image from the RibbonTextBox
    • Step 3b: Set a fixed width for the visual text area inside the RibbonTextBox
    • Step 3c: Set a fixed width for the label and text area inside the RibbonTextBox
  • Step 4: Viewing the templates of the basic ribbon controls
    • RibbonTab
    • RibbonButton
    • RibbonDropDownButton
    • RibbonSplitButton
    • RibbonCheckBox
    • RibbonTextBox
    • RibbonLabel
    • RibbonComboBox

Step 1: Creating a new application

Right now you should be able to create a new WPF application (WpfCustomRibbonControls) and reference the RibbonControlsLibrary.dll in this application. If you need help with this part, you should look over WPF Ribbon (CTP) – Part 1 – Add Ribbon and Customize

So, let’s suppose that we have a main window with this XAML:

<ribbon:RibbonWindow x:Class="WPFRibbonExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
Title="WPF Ribbon Example">
  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/RibbonControlsLibrary;component/Themes/Office2007Blue.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Window.Resources>
  <Grid>
    <ribbon:Ribbon Title="WPF Common Ribbon Controls Example">
      <ribbon:RibbonTab Name="CustomControlsTab" Label="Custom Controls Tab"></ribbon:RibbonTab>
    </ribbon:Ribbon>
  </Grid>
</ribbon:RibbonWindow>

and the following code behind:

namespace WpfCustomRibbonControls
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : RibbonWindow
  {
    public Window1()
    {
      InitializeComponent();
    }
  }
}

When it comes to creating your own ribbon control and adding it on the Ribbon, you have 2 choices:

  1. Derive a class from a basic(or custom) WPF control and also implement the IRibbonControl interface
  2. Change the template of an existing ribbon control in order to adapt it to your needs.

Step 2: Implementing the IRibbonControl interface

First of all we need to add a new class in the project. So right click the project, select Add and then Class. Name the class CustomEditBox and be sure to implement the IRibbonControl interface (otherwise you cannot add the control on the RibbonGroup), and also the TextBox WPF control, like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using Microsoft.Windows.Controls.Ribbon;

namespace WpfCustomRibbonControls
{
  class CustomEditBox : TextBox, IRibbonControl
  {
  }
}

For everybody’s surprise, the IRibbonControl interface does not have any methods to implement, it’s just a empty class that forces the programmer to add on the ribbon only certain controls.

So, the previous declared code is enough to get a normal textbox inside the ribbon, like so:

public partial class Window1 : RibbonWindow
{
  public Window1()
  {
    InitializeComponent();
    AddCustomEditBox();
  }

  private void AddCustomEditBox()
  {
    //create the group
    RibbonGroup group = new RibbonGroup();
    group.Command = new RibbonCommand() { LabelTitle = "Custom Edit Box" };

    //create the texbox and set a fixed width
    CustomEditBox textBox = new CustomEditBox();
    textBox.Width = 90;

    // add the textbox inside the group
    group.Controls.Add(textBox);

    // add the group on the tab
    CustomControlsTab.Groups.Add(group);
  }
}

If you run the application you will get the following textbox, which has a fixed size (and thus, solves the issue presented in the Part 3 of the tutorial). Of course, it does not have a label or an image next to it, as this is just a simple textbox. From this point on, you can use your imagination and create whatever control you want.

Step 3: Changing the template of an existing RibbonControl – e.g. RibbonTextBox

Let’s recall the previous issues that I mentioned for the RibbonTextBox, in the Part 3 of this tutorial.

Issues with the RibbonTextBox

    1. If you don’t specify any width for the RibbonGroup, while you enter text in the RibbonTextBox, the RibbonGroup will enlarge, like this:

  1. If you specify the width for the RibbonGroup, it will no longer enlarge when extra characters are typed in, but the textbox caret will continue to move to the right and dissapear from the visible text area, like this:

I will present an example of how to determine the layout of a control and change it to suit your needs.

First of all, in order to see the template of a control, you need a method that displays the template. This method may be something simple as the following one (in which I preferred to display the template using XML tags) or a more complex class, which also displays values for certain properties of the control (e.g. margin, width, height, color, padding etc).

namespace WpfCustomRibbonControls
{
  class Utils
  {
    public static void DisplayTemplateControl(DependencyObject element)
    {
       DisplayRecursivelyTemplateControl(element, 0);
    }

    protected static void DisplayRecursivelyTemplateControl(DependencyObject element, int level)
    {
      // get the type of the element
      string objType = element.GetType().ToString().Split('.').Last();

      // display indentation spaces
      for (int i = 0; i < level; i++)
      {
        Debug.Write("t");
      }
      // display starting tag
      Debug.WriteLine(string.Format("<{0}>", objType));

      // visit children recursively
      for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
      {
        DisplayRecursivelyTemplateControl(VisualTreeHelper.GetChild(element, i), level + 1);
      }

      // display indentation spaces
      for (int i = 0; i < level; i++)
      {
        Debug.Write("t");
      }
      // display ending tag
     Debug.WriteLine(string.Format("</{0}>", objType));
   }
  }
}

So, the next step is to create a derived class, from the RibbonTextBox, like this:

namespace WpfCustomRibbonControls
{
  class CustomRibbonTextBox : RibbonTextBox
  {
    public CustomRibbonTextBox()
    {
      // attach an event handler for the 'Loaded' event
      this.Loaded += new System.Windows.RoutedEventHandler(CustomRibbonTextBox_Loaded);
    }

    void CustomRibbonTextBox_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
      // display in the Output window the template of the RibbonTextBox
      Utils.DisplayTemplateControl(this);
    }
  }
}

As you can see, the CustomRibbonTextBox does not have anything in addition to the basic RibbonTextBox, it’s only purpose for now is to help us display the template and the layout of the RibbonTextBox. We need to display the template after the entire control has loaded, so the Loaded event is the best place to place the code.

Next, we need to add an image in the project, as we did in the previous tutorials and also, in the Utils class,  add a static method for loading a image:

public static BitmapImage GetImage(string relativeUri)
{
  BitmapImage bmp = new BitmapImage();
  try
  {
    bmp.BeginInit();
    bmp.UriSource = new Uri(relativeUri, UriKind.Relative);
    bmp.EndInit();
  }
  catch (Exception ex)
  {
    Debug.WriteLine(string.Format("Exception:{0} ... StackTrace:{1}", ex.Message, ex.StackTrace));
  }
  return bmp;
}

Of course, we have to add an instance of this control on the ribbon, inside the <em>Window1.xaml.cs</em> file. like so:

private void AddCustomRibbonTextBox()
{
  //create the group
  RibbonGroup group = new RibbonGroup();
  group.Command = new RibbonCommand() { LabelTitle = "Custom RibbonTextBox" };

  //create the texbox with a fixed width
  CustomRibbonTextBox textBox = new CustomRibbonTextBox();

  // create ribbon command in order to display the label and set the image
  RibbonCommand command = new RibbonCommand();
  command.LabelTitle = "Textbox label";
  command.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
  textBox.Command = command;

  // add the textbox inside the group
  group.Controls.Add(textBox);

  // add the group on the tab
  CustomControlsTab.Groups.Add(group);
}

And if we run the application, we will see the below visual control and inside the Output window this template:

<CustomRibbonTextBox>
  <StackPanel>
    <Image>
    </Image>
    <Label>
      <Border>
        <ContentPresenter>
        </ContentPresenter>
      </Border>
    </Label>
    <Border>
      <ScrollViewer>
        <Grid>
          <Rectangle>
          </Rectangle>
          <ScrollContentPresenter>
            <TextBoxView>
              <DrawingVisual>
              </DrawingVisual>
            </TextBoxView>
            <AdornerLayer>
            </AdornerLayer>
          </ScrollContentPresenter>
          <ScrollBar>
          </ScrollBar>
          <ScrollBar>
          </ScrollBar>
        </Grid>
      </ScrollViewer>
    </Border>
  </StackPanel>
</CustomRibbonTextBox>

Suprize! If you were expecting a simple textbox, you weren’t even remotely close! Even if you whought it is a collection of Image, Label and TextBlock, you’re still not right! it far more complex that that!  Maybe it’s the first time you see some of the controls – for me it surely was, as I did not know what ArdornerLayer or DrawingVisual are. The good news is that right now you know what the RibbonTextBox contains and you can change any element that you want. I will consider 3 examples:

  1. remove the image from the RibbonTextBox
  2. set a fixed size for the visual text area inside the RibbonTextBox
  3. set a fixed size for the label and the text area inside the RibbonTextBox

Step 3a: Removing the image from the RibbonTextBox

I know that the general look-and-feel of the Ribbon is that each control needs to have besides an optional label and actual content, a visual image that represents the control’s action. But sometimes you might have a lot of controls and you want to see us much as possible in the ribbon, without scrolling; then, you might consider reducing some space, and here is where the image removal part comes in – if we already have a label, the image just emphasizes the control’s action. It’s not a practice that I recommend, I’m sure that the users will be expecting an image there, as they are used with the office suite, but I’ve just given you a reason to why you would need such a change.

Probably the first idea to removing the image is to set the GroupSizeDefinitions with no image for the current control. Unfortunately, even if we would specify this for the previous instance of the CustomRibbonTextbox, the control would look the same.

// create the size definition for the control without image or label
 RibbonControlSizeDefinition sizeDef = new RibbonControlSizeDefinition();
 sizeDef.ImageSize = RibbonImageSize.Small;
 sizeDef.IsImageVisible = false;
 sizeDef.IsLabelVisible = false;
 // add the control's size defintion inside the group's size definition
 RibbonGroupSizeDefinition groupSizeDef = new RibbonGroupSizeDefinition();
 groupSizeDef.ControlSizeDefinitions = new System.Collections.ObjectModel.Collection<RibbonControlSizeDefinition>();
 groupSizeDef.ControlSizeDefinitions.Add(sizeDef);
 Collection<RibbonGroupSizeDefinition> groupSizeDefs = new Collection<RibbonGroupSizeDefinition>();
 groupSizeDefs.Add(groupSizeDef);
 // set the size definition
 textBox.SetValue(RibbonGroup.GroupSizeDefinitionsProperty, groupSizeDefs);

So, let’s create a new class named RibbonTextBoxWithoutImage:

namespace WpfCustomRibbonControls
{
  class RibbonTextBoxWithoutImage : RibbonTextBox
  {
    public RibbonTextBoxWithoutImage()
    {
      this.Loaded += new System.Windows.RoutedEventHandler(RibbonTextBoxWithoutImage_Loaded);
    }

    void RibbonTextBoxWithoutImage_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
      // try to find the image inside the current control
      var img = Utils.FindTemplateControl<Image>(this, false);
      // if the image exists, hide it and remove any margin
      if (img != null && img is Image)
      {
        (img as Image).Visibility = Visibility.Collapsed;
        img.Margin = new Thickness(0, 0, 0, 0);
        img.Width = 0;
        img.Height = 0;
      }
    }
  }
}

As you probably observed, I used another static method from the Utils class:

/// <summary>
/// Tries to find the first occurence of the specified type (T) inside the specified element's template. Returns null if no control of that type was found.
/// </summary>
/// <typeparam name="T">The type of the inner control you are looking for</typeparam>
/// <param name="element">The dependency object in which template you want to search</param>
/// <param name="includeCurrentElement">A boolean value indicating that the current element (actually starting element) should be included or not in the search</param>
/// <returns></returns>
public static T FindTemplateControl<T>(DependencyObject element, bool includeCurrentElement) where T : DependencyObject
{
  // if the current element is of type T and we want to include the current element in the search
  // then we found out inner control
  if (element is T && includeCurrentElement)
     return (T)element;

  // otherwise, look recursively in the inner children of the element
  for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
  {
    // we exclude only the starting element from the search, all children are included
    var result = FindTemplateControl<T>(VisualTreeHelper.GetChild(element, i), true);
    if (result != null)
       return result;
  }

  // if no element was found, return null
  return null;
}

We need to add an instance of the RibbonTextBoxWithoutImage on the ribbon, so let’s write in the Window1.xaml.cs file:

private void AddRibbonTextBoxWithoutImage()
{
  //create the group
  RibbonGroup group = new RibbonGroup();
  group.Command = new RibbonCommand() { LabelTitle = "RibbonTextBox Without Image" };

  //create the texbox with a fixed width
  RibbonTextBoxWithoutImage textBox = new RibbonTextBoxWithoutImage();

  // create ribbon command in order to display the label and set the image
  RibbonCommand command = new RibbonCommand();
  command.LabelTitle = "Textbox label";
  // even if we specify the image, it will not be displayed
  command.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
  textBox.Command = command;

  // add the textbox inside the group
  group.Controls.Add(textBox);

  // add the group on the tab
  CustomControlsTab.Groups.Add(group);
}

You can see now that we have the expected look for the control:

Compared to the CustomRibbonTextBox, the RibbonTextBoxWithoutImage not only doesn’t have the image displayed, but the entire space that would have been allocated for that image has dissapeared.

Step 3b: Set a fixed width for the visual text area inside the RibbonTextBox

So, let’s try to solve the RibbonTextBox width problem. We will create a RibbonTextBoxFixedTextWidth class, and change the layout in the Loaded event handler, like this:

namespace WpfCustomRibbonControls
{
    class RibbonTextBoxFixedTextWidth : RibbonTextBox
    {
        protected int textboxWidth;

        public RibbonTextBoxFixedTextWidth(int textboxWidth)
        {
            // keep the specified textbox width
            this.textboxWidth = textboxWidth;

            // add handler for the loaded event
            this.Loaded += new System.Windows.RoutedEventHandler(RibbonTextBoxFixedTextWidth_Loaded);
        }

        void RibbonTextBoxFixedTextWidth_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            // try to find the image inside the current control
            Image img = Utils.FindTemplateControl<Image>(this, false);

            // get the label
            Label lbl = Utils.FindTemplateControl<Label>(this, false);

            // get the scroll
            ScrollViewer scroll = Utils.FindTemplateControl<ScrollViewer>(this, false);

            // get the border
            Border border = this.Template.FindName("Bd", this) as Border;

            // if the border and label exist
            if (border != null && lbl != null && img != null)
            {
                // set the left and right margin and padding to 0
                border.Margin = new Thickness(0, border.Margin.Top, 0, border.Margin.Bottom);
                border.Padding = new Thickness(0, border.Padding.Top, 0, border.Padding.Bottom);
                // the actual width of the textbox has to be set to the border
                border.Width = textboxWidth;

                // update the scroll size to the new textbox width + scroll + border
                scroll.Width = textboxWidth
                    + Utils.GetHorizontalSpace(scroll.Margin)
                    + Utils.GetHorizontalSpace(scroll.Padding)
                    + Utils.GetHorizontalSpace(border.Margin)
                    + Utils.GetHorizontalSpace(border.Padding);

                // update the width of this control to fit all its inner controls (image + label + border)
                this.Width = textboxWidth
                    + lbl.ActualWidth + img.ActualWidth
                    + Utils.GetHorizontalSpace(border.BorderThickness)
                    + Utils.GetHorizontalSpace(border.Margin)
                    + Utils.GetHorizontalSpace(border.Padding)
                    + Utils.GetHorizontalSpace(img.Margin)
                    + Utils.GetHorizontalSpace(lbl.BorderThickness)
                    + Utils.GetHorizontalSpace(lbl.Margin)
                    + Utils.GetHorizontalSpace(lbl.Padding);
            }
        }
    }
}

So, let’s add 2 instances of this control in the main window, we will get the expected look and feel (the text control will no longer expand), but another problem arises:

private void AddRibbonTextBoxFixedTextWidth()
{
     //create the group
     RibbonGroup group = new RibbonGroup();
     group.Command = new RibbonCommand() { LabelTitle = "RibbonTextBox With Fixed Text Width" };

     //create the texboxes with fixed textarea width
     RibbonTextBoxFixedTextWidth textBox1 = new RibbonTextBoxFixedTextWidth(80);
     RibbonTextBoxFixedTextWidth textBox2 = new RibbonTextBoxFixedTextWidth(80);

     // create ribbon command in order to display the label and set the image for the textBox1
     RibbonCommand command1 = new RibbonCommand();
     command1.LabelTitle = "Small Label";
     command1.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
     textBox1.Command = command1;

     // create ribbon command in order to display the label and set the image for the textBox1
     RibbonCommand command2 = new RibbonCommand();
     command2.LabelTitle = "Large Textbox Label";
     command2.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
     textBox2.Command = command2;

     // add each textbox inside the group
     group.Controls.Add(textBox1);
     group.Controls.Add(textBox2);

     // add the group on the tab
     CustomControlsTab.Groups.Add(group);
}

Step 3c: Set a fixed width for the label and text area inside the RibbonTextBox

As you could see from the previous example, the 2 controls one under the other do not look alright. The most natural approach woudl be to align the labels and textboxes:

So, we will create a RibbonTextBoxFixedWidth class, and change the layout in the Loaded event handler:

namespace WpfCustomRibbonControls
{
    class RibbonTextBoxFixedWidth : RibbonTextBox
    {
        protected int textboxWidth;
        protected int labelWidth;

        public RibbonTextBoxFixedWidth(int labelWidth, int textboxWidth)
        {
            // keep the specified textbox and label width
            this.textboxWidth = textboxWidth;
            this.labelWidth = labelWidth;

            // add handler for the loaded event
            this.Loaded += new System.Windows.RoutedEventHandler(RibbonTextBoxFixedWidth_Loaded);
        }

        void RibbonTextBoxFixedWidth_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            // try to find the image inside the current control
            Image img = Utils.FindTemplateControl<Image>(this, false);

            // get the label
            Label lbl = Utils.FindTemplateControl<Label>(this, false);

            // get the scroll
            ScrollViewer scroll = Utils.FindTemplateControl<ScrollViewer>(this, false);

            // get the border
            Border border = this.Template.FindName("Bd", this) as Border;

            // if the border and label exist
            if (border != null && lbl != null && img != null)
            {
                // set the label's width
                lbl.Width = labelWidth;

                // set the left and right margin and padding to 0
                border.Margin = new Thickness(0, border.Margin.Top, 0, border.Margin.Bottom);
                border.Padding = new Thickness(0, border.Padding.Top, 0, border.Padding.Bottom);
                // the actual width of the textbox has to be set to the border
                border.Width = textboxWidth;

                // update the scroll size to the new textbox width + scroll + border
                scroll.Width = textboxWidth
                    + Utils.GetHorizontalSpace(scroll.Margin)
                    + Utils.GetHorizontalSpace(scroll.Padding)
                    + Utils.GetHorizontalSpace(border.Margin)
                    + Utils.GetHorizontalSpace(border.Padding);

                // update the width of this control to fit all its inner controls (image + label + border)
                this.Width = textboxWidth
                    + labelWidth + img.ActualWidth
                    + Utils.GetHorizontalSpace(border.BorderThickness)
                    + Utils.GetHorizontalSpace(border.Margin)
                    + Utils.GetHorizontalSpace(border.Padding)
                    + Utils.GetHorizontalSpace(img.Margin)
                    + Utils.GetHorizontalSpace(lbl.BorderThickness)
                    + Utils.GetHorizontalSpace(lbl.Margin)
                    + Utils.GetHorizontalSpace(lbl.Padding);
            }
        }
    }
}

So, if we add this control in the main window, we will get the following look and feel:

private void AddRibbonTextBoxFixedWidth()
{
    //create the group
    RibbonGroup group = new RibbonGroup();
    group.Command = new RibbonCommand() { LabelTitle = "RibbonTextBox With Fixed Text Width" };

    //create the texboxes with fixed width
    RibbonTextBoxFixedWidth textBox1 = new RibbonTextBoxFixedWidth(105, 80);
    RibbonTextBoxFixedWidth textBox2 = new RibbonTextBoxFixedWidth(105, 80);

    // create ribbon command in order to display the label and set the image for the textBox1
    RibbonCommand command1 = new RibbonCommand();
    command1.LabelTitle = "Small Label";
    command1.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
    textBox1.Command = command1;

    // create ribbon command in order to display the label and set the image for the textBox2
    RibbonCommand command2 = new RibbonCommand();
    command2.LabelTitle = "Larger Textbox Label";
    command2.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
    textBox2.Command = command2;

    // add each textbox inside the group
    group.Controls.Add(textBox1);
    group.Controls.Add(textBox2);

    // add the group on the tab
    CustomControlsTab.Groups.Add(group);
}

Step 4: Viewing the templates of the basic ribbon controls

I will consider all the basic ribbon contols and show you which is their template. For each, you will get a short description, using the Utils.DisplayTemplateControl method, but also a more complicated description, which uses a class that I made which displays the properties and inner elements for some of the wpf controls. I know that this class is still at the begining, I have a lot of work to do and a lot of other classes to add, but hopefully this version will be of help to you. Because it has a few hundred lines, I did not display if on the blog, but you can either get it from the source code or download it from here.

So, first, let’s suppose that we have a custom RibbonTab that we will add inside the main window and in this RibbonTab we will add a group with all the basic ribbon controls: RibbonButton, RibbonDropDownButton, RibbonSplitButton, RibbonTextBox, RibbonLabel, RibbonComboBox and RibbonCheckBox. The class would look like this:

namespace WpfCustomRibbonControls
{
    public class CustomRibbonTab : RibbonTab
    {
        public CustomRibbonTab()
        {
            this.Label = "Custom Ribbon Tab";
            CreateCustomControls();
        }

        private RibbonCommand CreateCommand(string label)
        {
            RibbonCommand cmd = new RibbonCommand();
            cmd.LabelTitle = "Ribbon Button";
            cmd.SmallImageSource = Utils.GetImage("images/positive-icon16.png");
            cmd.LargeImageSource = Utils.GetImage("images/positive-icon16.png");
            return cmd;
        }

        private void CreateCustomControls()
        {
            //create the group
            RibbonGroup group = new RibbonGroup();
            group.Command = new RibbonCommand() { LabelTitle = "Custom Controls" };

            RibbonButton btn = new RibbonButton();
            btn.Command = CreateCommand("RibbonButton");
            btn.Loaded += new RoutedEventHandler(control_Loaded);
            group.Controls.Add(btn);

            RibbonDropDownButton dropDown = new RibbonDropDownButton();
            dropDown.Command = CreateCommand("RibbonDropDownButton");
            dropDown.Loaded += new RoutedEventHandler(control_Loaded);
            group.Controls.Add(dropDown);

            RibbonCheckBox chk = new RibbonCheckBox();
            chk.Command = CreateCommand("RibbonCheckBox");
            chk.Loaded += new RoutedEventHandler(control_Loaded);
            group.Controls.Add(chk);

            RibbonComboBox combo = new RibbonComboBox();
            combo.Command = CreateCommand("RibbonComboBox");
            combo.Loaded += new RoutedEventHandler(control_Loaded);
            group.Controls.Add(combo);

            RibbonLabel label = new RibbonLabel();
            label.Loaded += new RoutedEventHandler(control_Loaded);
            label.Content = "RibbonLabel";
            group.Controls.Add(label);

            RibbonSplitButton splitBtn = new RibbonSplitButton();
            splitBtn.Loaded += new RoutedEventHandler(control_Loaded);
            splitBtn.Command = CreateCommand("RibbonSplitButton");
            group.Controls.Add(splitBtn);

            RibbonTextBox txt = new RibbonTextBox();
            txt.Loaded += new RoutedEventHandler(control_Loaded);
            txt.Command = CreateCommand("RibbonTextBox");
            group.Controls.Add(txt);

            this.Groups.Add(group);
            this.Loaded += new RoutedEventHandler(control_Loaded);
        }

        void control_Loaded(object sender, RoutedEventArgs e)
        {
            RibbonControlDebugger.DisplayObject((DependencyObject)sender);
        }
    }
}

As you can see, each control has the same small/large image and the apropriate label consits of the control’s name. Visually, they would look like this:

RibbonTab

<RibbonTab>
	<Grid>
		<Path>
		</Path>
		<Path>
		</Path>
		<Border>
			<Border>
			</Border>
		</Border>
		<Border>
			<TextBlock>
			</TextBlock>
		</Border>
		<Border>
		</Border>
	</Grid>
</RibbonTab>

The complex description of the RibbonTab’s template can be found here.

RibbonButton

<RibbonButton>
	<Border>
		<Border>
			<StackPanel>
				<Image>
				</Image>
				<TwoLineLabel>
					<TextBlock>
						<ContainerVisual>
							<Path>
							</Path>
						</ContainerVisual>
					</TextBlock>
				</TwoLineLabel>
			</StackPanel>
		</Border>
	</Border>
</RibbonButton>

The complex description of the RibbonButton’s template can be found here.

RibbonDropDownButton

<RibbonDropDownButton>
	<Grid>
		<RibbonToggleButton>
			<Border>
				<Border>
					<StackPanel>
						<Image>
						</Image>
						<TwoLineLabel>
							<TextBlock>
								<ContainerVisual>
									<Path>
									</Path>
								</ContainerVisual>
							</TextBlock>
						</TwoLineLabel>
						<Path>
						</Path>
					</StackPanel>
				</Border>
			</Border>
		</RibbonToggleButton>
		<Popup>
		</Popup>
	</Grid>
</RibbonDropDownButton>

The complex description of the RibbonDropDownButton’s template can be found here.

RibbonSplitButton

<RibbonSplitButton>
	<Grid>
		<Border>
			<Border>
				<StackPanel>
					<Image>
					</Image>
					<TextBlock>
					</TextBlock>
				</StackPanel>
			</Border>
		</Border>
		<Menu>
			<Border>
				<ItemsPresenter>
					<Grid>
						<MenuItem>
							<Grid>
								<Border>
									<Border>
										<StackPanel>
											<TextBlock>
											</TextBlock>
											<Path>
											</Path>
										</StackPanel>
									</Border>
								</Border>
								<Popup>
								</Popup>
							</Grid>
						</MenuItem>
					</Grid>
				</ItemsPresenter>
			</Border>
		</Menu>
	</Grid>
</RibbonSplitButton>

The complex description of the RibbonSplitButton’s template can be found here.

RibbonCheckBox

<RibbonCheckBox>
	<StackPanel>
		<Border>
			<Grid>
				<Border>
				</Border>
				<Path>
				</Path>
			</Grid>
		</Border>
		<TextBlock>
		</TextBlock>
	</StackPanel>
</RibbonCheckBox>

The complex description of the RibbonCheckBox’s template can be found here.

RibbonTextBox

<RibbonTextBox>
	<StackPanel>
		<Image>
		</Image>
		<Label>
			<Border>
				<ContentPresenter>
				</ContentPresenter>
			</Border>
		</Label>
		<Border>
			<ScrollViewer>
				<Grid>
					<Rectangle>
					</Rectangle>
					<ScrollContentPresenter>
						<TextBoxView>
							<DrawingVisual>
							</DrawingVisual>
						</TextBoxView>
						<AdornerLayer>
						</AdornerLayer>
					</ScrollContentPresenter>
					<ScrollBar>
					</ScrollBar>
					<ScrollBar>
					</ScrollBar>
				</Grid>
			</ScrollViewer>
		</Border>
	</StackPanel>
</RibbonTextBox>

The complex description of the RibbonTextBox’s template can be found here.

RibbonLabel

<RibbonLabel>
	<Border>
		<ContentPresenter>
		</ContentPresenter>
	</Border>
</RibbonLabel>

The complex description of the RibbonLabel’s template can be found here.

RibbonComboBox

<RibbonComboBox>
	<Grid>
		<Popup>
		</Popup>
		<Border>
		</Border>
		<TextBox>
			<ScrollViewer>
				<Grid>
					<Rectangle>
					</Rectangle>
					<ScrollContentPresenter>
						<TextBoxView>
							<DrawingVisual>
							</DrawingVisual>
						</TextBoxView>
						<AdornerLayer>
						</AdornerLayer>
					</ScrollContentPresenter>
					<ScrollBar>
					</ScrollBar>
					<ScrollBar>
					</ScrollBar>
				</Grid>
			</ScrollViewer>
		</TextBox>
		<ToggleButton>
			<Border>
				<Border>
					<Path>
					</Path>
				</Border>
			</Border>
		</ToggleButton>
	</Grid>
</RibbonComboBox>

The complex description of the RibbonComboBox’s template can be found here.

Source Code

You can download the source code for part 5 of the tutorial from here.

Posted in WPF Ribbon and tagged as , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.