In This Article

MVVM Support

This topic discusses the overall MVVM-friendly product architecture of Bars controls, along with the optional open source companion Bars MVVM library.

The MVVM library contains a full set of view model classes, template selector classes, and related view templates that support easy MVVM-based configuration and management of Bars controls. It is demonstrated in the main Bars "Document Editor" demo in the sample project, where a very large and complex ribbon hierarchy is constructed using MVVM techniques.

Bars Product Architecture

All of the Bars controls have been purposefully designed to be compatible with MVVM techniques.

Before getting into the contents of the MVVM library itself, let's examine the overall Bars product architecture and how its controls work with view models, template selectors, and view templates.

Items Controls

Many Bars controls, especially those in the ribbon hierarchy, inherit the native ItemsControl class. This is key to the principle of supporting MVVM because it allows you to bind a collection of items (generally view models) to a control's ItemsSource. The control's item container generator will then examine each item and if it is not an allowed "container" element for the ItemsControl, it will ask for a "container" element to be generated. This is where ItemContainerTemplateSelector classes come into play.

Item Container Template Selectors

Bars controls that derive from ItemsControl make heavy use of ItemContainerTemplateSelector classes. This lesser-known class type works similarly to the DataTemplateSelector class, where an item (usually a view model) is passed into a SelectTemplate method, along with a control reference. The DataTemplateSelector.SelectTemplate method passes in the container control instance as the control reference, whereas the ItemContainerTemplateSelector.SelectTemplate method passes in the owner ItemsControl as the control reference.

The point of an ItemContainerTemplateSelector is to generate a "container" element for an ItemsControl's item. The SelectTemplate method returns an ItemContainerTemplate (a class that inherits DataTemplate) that contains the element hierarchy to generate. The root element generated from that ItemContainerTemplate will be used as the "container" for the item, and the item will be set as that "container" element's DataContext.

Ribbon Example

As an example to the above process, let's consider the Ribbon control. It inherits Selector, which in turn inherits native ItemsControl. It's set up to call into the Ribbon.ItemContainerTemplateSelector that is currently assigned (if any) to try and generate a RibbonTabItem "container" element for any item in its ItemsSource that doesn't derive from RibbonTabItem.

Now say that a custom ribbon tab view model class (call it RibbonTabViewModel) is the type of item bound to the ribbon's ItemsSource, and there is one instance of the class for each tab in the ribbon.

It's the responsibility of the SelectTemplate method in the ItemContainerTemplateSelector assigned to Ribbon.ItemContainerTemplateSelector to look at the RibbonTabViewModel and return an ItemContainerTemplate that contains a RibbonTabItem control at its root. The RibbonTabItem XAML in the ItemContainerTemplate should have bindings configured from the view model to the control.

Note

Bars controls are set up to pass an ItemContainerTemplateSelector that is assigned down to any child controls. For instance, setting the Ribbon.ItemContainerTemplateSelector property will pass that ItemContainerTemplateSelector down through tabs, groups, and even into popup menus. In this way, the same template selector instance can be reused throughout the control hierarchy.

With all of that in place, when a Ribbon sees a RibbonTabViewModel item in its ItemsSource, it will generate a RibbonTabItem "container" that will have its DataContext set as the RibbonTabViewModel instance, and the tab will appear in the ribbon UI.

Properties on the RibbonTabViewModel may be modified, and as long as INotifyPropertyChanged is implemented on the view model class, the property changes will flow into the generated RibbonTabItem via the bindings that were set up in the ItemContainerTemplate.

Tip

View model classes can inherit the ObservableObjectBase class from the Shared Library to easily implement INotifyPropertyChanged.

RibbonGallery and BarMenuGallery are graphically-rich list controls that support selection of anything from colors to text styles. Even when a ribbon hierarchy is constructed in pure XAML, gallery controls must still use MVVM for their items.

While galleries can use logic like above with an ItemContainerTemplateSelector to generate BarGalleryItem "container" elements for their items, the actual items should always be some sort of view model. The visual content within a displayed gallery item is selected by a custom DataTemplateSelector instance set to the gallery's ItemTemplateSelector property. The DataTemplateSelector.SelectTemplate property is passed the view model item and returns a DataTemplate to use as the UI for the gallery item.

The DataTemplate may contain the complete UI for the gallery item, or it may include a custom element that knows how to measure and render itself in code-behind. The DataContext for the elements in the DataTemplate will be the gallery item view model, allowing for the view model's properties to be bound into any elements within the DataTemplate.

See the Gallery topic for more information on galleries.

Backstage Tab Content

A RibbonBackstage control is effectively a tab control where each item generates a RibbonBackstageTabItem "container" element if one isn't used directly as the item. Note that buttons and separators can also be used as backstage items.

If the RibbonBackstage.ItemsSource is set to a collection of view models, the RibbonBackstage.ContentTemplateSelector can be set to a DataTemplateSelector that will return the DataTemplate for each tab's content. It's up to the DataTemplateSelector.SelectTemplate method to examine the backstage tab view model and return the appropriate DataTemplate for the related backstage tab's content.

Alternatively, if distinct view model types (InfoRibbonBackstageTabViewModel, NewRibbonBackstageTabViewModel, etc.) are used as the backstage tab view models, the Resources of the RibbonBackstage control or the containing Window can contain implicit DataTemplate instances with their DataType attributes set to the related view model type, like this:

<DataTemplate DataType="{x:Type local:InfoRibbonBackstageTabViewModel}">
	<!-- 'Info' tab content here -->
</DataTemplate>

<DataTemplate DataType="{x:Type local:NewRibbonBackstageTabViewModel}">
	<!-- 'New' tab content here -->
</DataTemplate>

When using implicit DataTemplate resources, no ContentTemplateSelector is necessary.

See the Backstage topic for more information on backstage.

The RibbonFooterControl is a ContentControl and supports both DataTemplateSelector and implicit DataTemplate-based content selection.

See the Footer topic for more information on ribbon footers.

Container Element Summary

This table summarizes most of the ItemsControl-based controls in Bars and which "container" elements they expect to be generated from an ItemContainerTemplateSelector:

ItemsControl Expected Container Element(s)
BarContextMenu Various Bars controls for menu context.
BarMenuGallery BarGalleryItem.
BarMenuItem Various Bars controls for menu context.
BarPopupButton Various Bars controls for menu context.
BarSplitButton Various Bars controls for menu context.
BarSplitMenuItem Various Bars controls for menu context.
BarSplitToggleButton Various Bars controls for menu context.
MiniToolBar Various Bars controls for toolbar context.
Ribbon RibbonTabItem.
RibbonBackstage RibbonBackstageTabItem, RibbonBackstageHeaderButton, or RibbonBackstageHeaderSeparator.
RibbonContextualTabGroupItemsControl RibbonContextualTabGroup.
RibbonControlGroup Various Bars controls for ribbon context.
RibbonGallery BarGalleryItem.
RibbonGroup RibbonControlGroup, RibbonMultiRowControlGroup, or various Bars controls for ribbon context.
RibbonMultiRowControlGroup RibbonControlGroup or various Bars controls for ribbon context.
RibbonQuickAccessToolBar Various Bars controls for ribbon context.
RibbonTabItem RibbonGroup.
RibbonTabRowToolBar Various Bars controls for toolbar context.
StandaloneToolBar Various Bars controls for toolbar context.
TaskTabControl TaskTabItem.

Open Source MVVM Library

The full source of the helpful companion MVVM library that contains Bars-related view model classes, template selector classes, and related view templates is available in GitHub at:

https://github.com/Actipro/WPF-Controls/tree/main/Source/Bars.Mvvm

If you wish for your Bars controls to be managed with MVVM, but don't wish to use our pre-built MVVM library, its source code is still an excellent reference for how you can integrate custom view models, template selectors, and templates with Bars controls.

MVVM Library Contents

The MVVM library contains many types and templates to assist in managing Bars control hierarchies using MVVM techniques.

Template Selectors

As described earlier in this topic, the Bars product has been designed to make use of ItemContainerTemplateSelector and DataTemplateSelector instances to associate view models with related view templates. The MVVM library includes numerous view model types and offers several template selectors classes that map the view models to predefined view templates.

For Bar Controls

The BarControlTemplateSelector class inherits ItemContainerTemplateSelector and helps generate "container" elements for all of the bar control view models described later in this topic.

When using the MVVM library with Bars controls, an instance of BarControlTemplateSelector should be set to the root bar control's ItemContainerTemplateSelector property, such as Ribbon.ItemContainerTemplateSelector or StandaloneToolBar.ItemContainerTemplateSelector. The template selector will propagate down the hierarchy of bar controls automatically.

The RibbonFooterContentTemplateSelector class inherits DataTemplateSelector and provides the view DataTemplate to use for ribbon footer content view models described later in this topic that are passed into the RibbonFooterViewModel.Content property. An instance of the template selector class is automatically assigned to the RibbonFooterViewModel.ContentTemplateSelector property.

The BarGalleryItemTemplateSelector class inherits DataTemplateSelector and provides the view DataTemplate to use for gallery item view models described later in this topic. An instance of the template selector needs to be assigned to each gallery control, which can be done through the BarGalleryViewModel.ItemTemplateSelector property.

View Models

The MVVM library contains many view models that can drive the various Bars controls via MVVM.

Bar Control View Models

The following table shows various bar control view model types defined in the MVVM library, and maps them to the control concepts they are pre-configured to generate via a BarControlTemplateSelector instance.

Name Description
BarButtonViewModel Regular button control.
BarCheckBoxViewModel Checkbox control.
BarComboBoxViewModel Combobox control.
BarGalleryViewModel Gallery control.
BarHeadingViewModel Heading control.
BarKeyedObjectViewModelBase Abstract base class for a control with a string keys.
BarPopupButtonViewModel Popup button control.
BarSeparatorViewModel Separator control.
BarSizeSelectionMenuGalleryViewModel Size-selection gallery control.
BarSplitButtonViewModel Regular split button control.
BarSplitToggleButtonViewModel Toggle split button control.
BarTextBoxViewModel Textbox control.
BarToggleButtonViewModel Toggle button control.
MiniToolBarViewModel Mini-toolbar control.
RibbonApplicationButton Application button control.
RibbonBackstageHeaderButtonViewModel Backstage header button control.
RibbonBackstageHeaderSeparatorViewModel Backstage header separator control.
RibbonBackstageTabViewModel Backstage tab control.
RibbonContextualTabGroupViewModel Contextual tab group control.
RibbonControlGroupViewModel Control group control.
RibbonFooterViewModel Footer control.
RibbonGroupLauncherButtonViewModel Group launcher button control.
RibbonGroupViewModel Group control.
RibbonMultiRowControlGroupViewModel Multi-row control group control.
RibbonQuickAccessToolBarViewModel Quick access toolbar control.
RibbonTabRowToolBarViewModel Tab row toolbar control.
RibbonTabViewModel Tab control.
RibbonViewModel Ribbon control.
StandaloneToolBarViewModel Standalone toolbar control.
Note

Some view models may generate a different control based on the usage context. For instance, a BarButtonViewModel will generate a BarButton control when in a ribbon/toolbar context, and a BarMenuItem control when in a menu context.

The following table shows the ribbon footer content view model types defined in the MVVM library, which are supported by the RibbonFooterContentTemplateSelector class out of the box. Instances of these view model types can be assigned to the RibbonFooterViewModel.Content property when a footer message should be displayed.

Name Description
RibbonFooterSimpleContentViewModel Specifies an ImageSource and text message to render in the ribbon footer.

The following table shows the gallery item view model types defined in the MVVM library, which are supported by the BarGalleryItemTemplateSelector class out of the box. Instances of these view model types can be bound into the ItemsSource of any gallery control.

Name Description
IBarGalleryItemViewModel An interface that provides the common requirements of a gallery item view model.
BarGalleryItemViewModel<T> Has a generic type parameter for a related value. Can be used directly or inherited for specialized gallery item view model types.
ColorBarGalleryItemViewModel Represents a Color value, used for any kind of color picker gallery.
EnumBarGalleryItemViewModel<T> Has a generic type parameter for a related enumeration value. Can be used directly or inherited for specialized gallery item view model types. See "Using EnumBarGaleryItemViewModel" section below for more details.
FontFamilyBarGalleryItemViewModel Represents a font family name, used for font comboboxes.
FontSizeBarGalleryItemViewModel Represents a font size, used for font size comboboxes.
SymbolBarGalleryItemViewModel Represents a symbol (e.g., copyright sign) string, used to insert a symbol into a document. Rendered by a SymbolPresenter element.
TextBarGalleryItemViewModel Represents a simple text string.
TextStyleBarGalleryItemViewModel Represents a text style for a document, which stores information like font, color, bold, etc. Rendered by a TextStylePresenter element.

Using EnumBarGalleryItemViewModel

Instances of the EnumBarGalleryItemViewModel<T> class (where T is an enumeration type) are typically generated by the EnumBarGalleryItemViewModel<T>.CreateCollection method. This static method uses reflection to automatically generate a view model for every value that is defined for the enumeration.

By default, the Label and Value are populated from the declaration, but attributes can also be used to define additional information, customize the label, or indicate a value should be skipped.

Attribute Class Property Name Description
System.ComponentModel.EditorBrowsableAttribute State When set to EditorBrowsableState.Never, the value will be ignored when generating the collection.
System.ComponentModel.DescriptionAttribute Description Defines a custom Label replacing the declared name.
System.ComponentModel.DataAnnotations.DisplayAttribute Name Defines a custom Label replacing the declared name. If DescriptionAttribute is also defined, this attribute property is ignored.
System.ComponentModel.DataAnnotations.DisplayAttribute ShortName Defines a custom Label replacing the declared name. If either DescriptionAttribute or DisplayAttribute.Name is also defined, this attribute property is ignored.
System.ComponentModel.DataAnnotations.DisplayAttribute GroupName Populates the Category property that is used for grouping.
System.ComponentModel.DataAnnotations.DisplayAttribute Description Populates the Description property that is used for tooltips.
System.ComponentModel.DataAnnotations.DisplayAttribute Order (Default = 10000) Used to determine the order in which items appear in the collection. Values lower than the default will appear before the items with default order, and those with values higher than the default will appear after the items with default order.
Important

Since the CreateCollection method uses DisplayAttribute to initialize some view model properties and that attribute supports localization, any view models created by this method will reflect the locale at the time they were created. If the locale changes, call EnumBarGalleryItemViewModel<T>.RefreshFromAttributes to update properties from current attribute data.

Tip

Use the EnumBarGalleryItemViewModel<T>.CreateCollection method to easily populate a Combobox with all the available values of an enumeration.

Root Bar Control Styles

The BarsMvvmResourceKeys class provides access to several pre-configured Style instances in Resources that bind root bar controls to their related view model. It is assumed that the appropriate view model is set to the bar control's DataContext property in your code.

Property Name Description
RibbonStyle Sets up bindings on a Ribbon control to a RibbonViewModel instance.
StandaloneToolBarStyle Sets up bindings on a StandaloneToolBar control to a StandaloneToolBarViewModel instance.
Tip

It is recommended that these styles are used on the root bar controls when using the MVVM library.

This example shows how to use a root bar control Style on a Ribbon:

xmlns:bars="http://schemas.actiprosoftware.com/winfx/xaml/bars"
xmlns:themes="http://schemas.actiprosoftware.com/winfx/xaml/themes"
...
<bars:Ribbon x:Name="ribbon"
	DataContext="{Binding Ribbon}"
	Style="{StaticResource {x:Static themes:BarsMvvmResourceKeys.RibbonStyle}}"
	/>

Bar Image Provider

The IBarImageProvider interface defines the base requirements for a class that can provide images for a given set of options.

The BarImageOptions class designates a desired image size via its Size property, whose values can be Small (16x16), Medium (24x24), or Large (32x32). It also designates an optional ContextualColor that some implementations may use to show a swatch color on top of an image. This feature can be used for images that show the current text color.

The BarImageProvider class implements IBarImageProvider and allows you to Register an image factory function for a string key. The key should generally match the key for the related bar control.

The factory function is called when the GetImageSource method is invoked and passes a BarImageOptions instance, while expecting an ImageSource in return.

This example demonstrates a registration, and assumes your application has an ImageLoader.GetIcon method that loads the image with the specified filename:

imageProvider.Register("AlignCenter", options => ImageLoader.GetIcon("AlignTextCenter16.png"));

Call the Unregister method to later unregister a factory function for a particular key if needed.

Customizing View Models and Template Selectors

Any of the template selectors described above can be augmented in case the built-in functionality is not enough, or new view model classes are used.

Adding a View Model Property

For instance, say the BarButtonViewModel class is missing a Tag property that you wish to set to carry other custom data. Create a class that inherits BarButtonViewModel and adds a Tag property. Update the BarControlTemplateSelector.BarButtonDefaultTemplate property to point to a DataTemplate that is a clone of the default DataTemplate, but also adds a binding of the BarButton.Tag property to the view model's Tag property.

Third-Party Control Support

In another scenario, perhaps you wish to introduce a brand-new bar control view model class for a third-party control. Create a view model class with the properties you wish to bind to the control. Next, create a class that inherits BarControlTemplateSelector and override its SelectTemplate method to handle the new view model as an item. It should return a new DataTemplate that contains the third-party control and appropriate bindings to the view model. Be sure to call the base SelectTemplate method for other bar control view model types so they are still handled properly. Set an instance of the custom BarControlTemplateSelector-based class to all root bar controls like Ribbon or StandaloneToolBar.

The most common customization is likely for gallery items since these tend to be more application specific. When creating a new kind of gallery item, create a view model class that inherits BarGalleryItemViewModel<T> and has whatever other properties are necessary for the gallery item to be identifiable and capable of rendering in UI. Next, create a class that inherits BarGalleryItemTemplateSelector and override its SelectTemplate method to handle the new view model as an item. It should return a new DataTemplate that contains the UI elements used to render the gallery item, along with appropriate bindings to the view model. Be sure to call the base SelectTemplate method for other gallery item view model types so they are still handled properly. Set an instance of the custom BarGalleryItemTemplateSelector-based class to any galleries that host the new kind of gallery item.