Monday, November 3, 2008

WPF Ribbon Control

Scott Guthrie announced the new Ribbon Control a few days ago, so I thought give it a shot to see how it works.

Referencing the Ribbon
First, create a window and import the control's namespace. If you're using the dll provided in RibbonBinaries folder, you can not use namespace mapped to Xmlns! This is because the file "AssemblyAttrs.cs" is not included in the project file, so the Xml namespace won't map to CLR namespace correctly. To fix this, you should recompile the control. Open the project file and add the existing "AssemblyAttrs.cs" file to the project, remove the redundant code that is duplicated in AssemblyInfo.cs, and build. Use the newly compiled dll file instead. After doing so, you can import the mapped namespace :

<Window x:Class="MSRibbon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rib="http://schemas.microsoft.com/wpf/2008/ribbon"
Title="Main Window" Height="600" Width="800">
<
DockPanel>
</
DockPanel>
</
Window>

Adding a ribbon control to the window is a no brainer. Just add a ribbon control and dock it to the Top.

<DockPanel>
<
rib:Ribbon DockPanel.Dock="Top">

</
rib:Ribbon>
</
DockPanel>

Note : Office UI Design guidelines clearly says that you SHOULD ALWAYS dock the Ribbon to the top of your window.


Adding Controls to Ribbon
Next thing would be to add a few controls to our ribbon. In this new ribbon, unlike other ribbons in the market, the approach to add controls to the ribbon is more View-Model centric, meaning you always use a RibbonCommand, which is a subclass of RoutedCommnad, to specify a tool's Title, Description, Tooltip, Icon, etc. Let's create some Ribbon Commands now :
<Window.Resources>
<
rib:RibbonCommand x:Key="CopyCommand" LabelTitle="Copy"
SmallImageSource="Images\Copy-small.png"
LargeImageSource="Images\Copy-large.png"
ToolTipTitle="Copy"
ToolTipDescription="Copies the selected data into clipboard."
Executed="CopyCommand_Executed" />
<
rib:RibbonCommand x:Key="PasteCommand" LabelTitle="Paste"
SmallImageSource="Images\Paste-small.png"
LargeImageSource="Images\Paste-large.png"
ToolTipTitle="Paste"
ToolTipDescription="Pastes the data from the clipboard."
Executed="PasteCommand_Executed" />
<
rib:RibbonCommand x:Key="CutCommand" LabelTitle="Cut"
SmallImageSource="Images\Cut-small.png"
LargeImageSource="Images\Cut-large.png"
ToolTipTitle="Cut"
ToolTipDescription="Cuts the data from the window."
Executed="CutCommand_Executed" />
<
rib:RibbonCommand x:Key="ClipboardGroupCommand" LabelTitle="Clipboard" />
</
Window.Resources>

We can use these commands to build up our ribbon's UI, in a much simpler and cleaner way :

<rib:Ribbon DockPanel.Dock="Top" >
<
rib:RibbonTab Label="Home">
<
rib:RibbonGroup Command="{StaticResource ClipboardGroupCommand}">
<
rib:RibbonButton Command="{StaticResource CutCommand}" />
<
rib:RibbonButton Command="{StaticResource CopyCommand}" />
<
rib:RibbonButton Command="{StaticResource PasteCommand}" />
</
rib:RibbonGroup>
</
rib:RibbonTab>
</
rib:Ribbon>

Ribbon-Basic Basic Riboon control in Aero theme

So far we have an incomplete Ribbon control on our hands. Let's move ahead and see how we can satisfy other ribbon's requirements.


Application Menu and RibbonWindow

Switching to a Ribbon Window as simple as changing the type of your Window to RibbonWindow and you're all set. As for the Application Button goes, you can set it through ApplicationMenu property of your Ribbon control :

<rib:Ribbon.ApplicationMenu>
<
rib:RibbonApplicationMenu Command="{StaticResource ApplicationCommand}" />
</
rib:Ribbon.ApplicationMenu>
Of course you need a RibbonCommand for the application button as well. So, just set the image in a RibbonCommand and run :
<rib:RibbonCommand x:Key="ApplicationCommnad"
LargeImageSource="Images\App.png"
SmallImageSource="Images\App-small.png" />
Note : To my surprise, if you only add a 32 x 32 image to your application button, it will show up as empty in Aero skin! You also need to add a Small image (16 x 16) to make it work in Aero skin. This obviously violates many of the the Office UI Licensing rules that states The Application Button MUST be round or The Application Button MUST have approximately a 36 pixel diameter. Both 16 x 16 image size and application button shape in Aero which looks like a rectangle with round edges, violates the mentioned rules. There are other things that violates the Office UI Licensing like Group Labels MUST have a background color that is distinct from the background group, which as you can see in the above picture, it is not the case, and the Group Label "Clipboard" has the same background as the group. All these makes me wonder if we can use this skin at all!!


So, let's change the skin to a non-violating skin, add some application actions to our Application Menu and see how the Ribbon control looks like. To change the skin via Xaml, merge the skin resource you want with you application resources :

<Application.Resources>
<
ResourceDictionary Source="/RibbonControlsLibrary;component/Themes/Office2007Blue.xaml"/>
</
Application.Resources>
Now, let's add some application related actions to our Application Menu. We'll add application wide actions like New Open, Close and Save for the purpose of this demo. To add to Application Menu items in Xaml, add it to Items collection of you ApplicationMenu object. ApplicationMenu also has a Footer property which you can add other controls to.
<rib:Ribbon.ApplicationMenu>
<
rib:RibbonApplicationMenu Command="{StaticResource ApplicationCommnad}">
<
rib:RibbonApplicationMenu.Items>
<
rib:RibbonApplicationMenuItem Command="{StaticResource NewAppCommand}" />
<
rib:RibbonApplicationMenuItem Command="{StaticResource OpenAppCommand}" />
<
rib:RibbonApplicationMenuItem Command="{StaticResource CloseAppCommand}" />
<
rib:RibbonApplicationMenuItem Command="{StaticResource SaveAppCommand}" />
<
rib:RibbonSeparator />
<
rib:RibbonApplicationMenuItem Command="{StaticResource ExitAppCommand}" />
</
rib:RibbonApplicationMenu.Items>
<
rib:RibbonApplicationMenu.Footer>
<
StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<
rib:RibbonButton Command="{StaticResource OptionsAppCommand}" Margin="5" />
<
rib:RibbonButton Command="{StaticResource ExitAppCommand}" Margin="5" />
</
StackPanel>
</
rib:RibbonApplicationMenu.Footer>
</
rib:RibbonApplicationMenu>
</
rib:Ribbon.ApplicationMenu>

Due to the fact that we can reuse RibbonCommands in multiple places, we're sharing our ExitAppCommand both in ApplicationMenu footer and as a Application menu item. Here's how it looks :

AppMenu
Application Menu


Localization

Like standard WPF Controls you should be able to set the FlowDirection of RibbonWindow to RightToLeft to mirror the window and its content, but if you do so, the control will not work correctly. Even if you set the flow direction of the ribbon control that resides in a RibbonWindow, there are rendering problems. If you need to use the RibbonControl in a RightToLeft reading order, you can use a normal WPF Window which renders fine and mirrored Riboon will look fine.


WindowedRTLRibbon
Control behavior is correct when hosted in a normal WPF Window



ControlInRibbonWindow
Control Renders incorrectly over the RibbonWindow's Non-client area

You can use any standard localization procedure you do with normal WPF controls. Since almost everything you need to localize is a RibbonCommand, you only need to keep your commands localizable. I couldn't find clues on how to describe internal Ribbon strings, which apparently you can not. The finalized output that is localized in Persian (fa-ir) culture would look something like this :

LocalizedRibbon
Localized Ribbon control

Summary
Recently provided Ribbon control is a lightweight implementation office Ribbon control. Although this is a great control, it lacks functionality in the area of Localization. This is an initial release and I hope it gets better by next versions. Remember to completely read the Office UI Guideline document before you start developing application that uses a Ribbon control.

You can download related files here.


Submit this story to DotNetKicks Shout it

8 comments:

خودم said...

Hi,
I really respect your posts.
Thanks for Introduction.
Keep writing.

ruN said...

Hi!

I cant get the reference working, which means that I cannot use http://schemas.microsoft.com/wpf/2008/ribbon

I've tried finding the AssemblyAttrs.cs file, but I can't find it - where is it located, and furthermore, - where can I find the RibbonBinaries folder containing the DLL?

Regards

Anonymous said...

where I can find this control.
did you have any links to related assemblies?

Hadi Eskandari said...

@ruN : There is an AssemblyInfo in Properties section of the project. Just add a XmlnsDefinition attribute on the assembly and control's namespace and recompile. It should work then.

@Anonymous : It's a little complicated. Although the controls are free, you need to accept an agreement before you can download YOUR copy of the control. You need to download it from Office UI Licensing site see here for step by step instructions.

ruN said...

Hello Hadi
I amcurrently experimenting with the ribbon control, but the only way I am able tor use it i xaml, is to refer to the clr-namespace instead of the xaml-namespace. I've explained more here: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6ba0dbc9-68fc-4bbc-85b9-61efff264f3b
Would you be kind and explain how you got it to work?
Your help will be greatly appriciated

Regards

Hadi Eskandari said...

@ruN : I think it is clear enough how to fix the problem. The distributed dll has this problem so you just need to add related attribute to the assembly and recompile : "To fix this, you should recompile the control. Open the project file and add the existing "AssemblyAttrs.cs" file to the project, remove the redundant code that is duplicated in AssemblyInfo.cs, and build."

Anonymous said...

Concerning the localization of the ribbon control i can't find any problems:
1-For the text: you can do it by setting all the textual properties (tooltip,tooltipdescription, etc..) from code behind instead of being set inside the xaml, that way you can reference your resources dll files easily.

2-For the layout: the control already supports FlowDirection property and layouts the controls as expected very well.

Regards.

flashbeir said...

Ribbon control looks great but how can you interact with pages?
Suppose you have a ribbon button that marks a selected text on the page bold.

How do you do that?