SandRibbon for WPF User Guide

Live Preview

Back to Table of Contents

Preview Events

The RibbonControl class is responsible for triggering live preview events. SandRibbon classes you will typically use that derive from this are Button and MenuItem, which means GalleryButton and ComboBoxItem are included too as subclasses of Button.

When the mouse enters one of these controls hosted in a popup, the LivePreview event is fired on your Ribbon. When the mouse enters one of these controls hosted directly on the ribbon (such as a gallery button in a ribbon gallery) the same event is fired after a short delay, to ensure the user really does mean to hover over it. The method handling the event is passed arguments containing the control the mouse was moved over. Your application can therefore perform an action depending on this control.

The ILivePreview Interface

Of course, simply applying an action on live preview is not enough - the action will subsequently have to be undone as the user moves the mouse away from the control they were previewing, or away from the ribbon entirely, or even if they activate the control. The live preview operation should always be undone even if the control is subsequently activated, whereupon your application will perform the control action for real.

In order to simplify the process of applying live preview, we supply the ILivePreview interface. Your application provides SandRibbon with an instance of a (usually) simple class that implements this interface, then SandRibbon can undo the live preview at the appropriate time by calling a method on the class.

The interface contains two methods: ActivatePreview and RemovePreview. In your handler for the LivePreview event you set e.PreviewObject to an instance of your utility class that implements the interface. As soon as the event returns the ActivatePreview method is called. At some point later, but definitely before any other LivePreview event is raised or any control is activated, the RemovePreview method is called. Each method is guaranteed to be called only once.

Example Implementation (Formatting)

The RichTextBox control supplied with WPF is an excellent candidate for live preview and its API is very much compatible with the concept. To apply formatting to a text selection in a rich text box you call the selection's ApplyPropertyValue method, passing a property and a value, and that value is applied to all elements in the selection which support that property. Also, the contents of a text selection are easily persisted and then restored later.

We will therefore design a simple class that takes a text selection, a property, and a value in its constructor. The text selection will come from the active RichTextBox and the property and value will depend on what type of control is being previewed. For example, if the control is a ColorButton (which occur only in ColorPickers) the property will be ForegroundProperty and the value will be the color of the button being previewed. Our class must save the contents of the selection just before applying the preview, and restore them when the preview is being removed.

private class PreviewTextFormatting : ILivePreview
{
	private TextSelection selection;
	private DependencyProperty property;
	private object value;
	private MemoryStream stream;

	public PreviewTextFormatting(TextSelection selection, DependencyProperty property, object value)
	{
		this.selection = selection;
		this.property = property;
		this.value = value;
	}

	public void ActivatePreview()
	{
		// Save the contents of the selection for later undoing of the preview operation
		stream = new MemoryStream();
		selection.Save(stream, DataFormats.Xaml);

		// Apply the new property value
		selection.ApplyPropertyValue(property, value);
	}

	public void RemovePreview()
	{
		// Load the contents back
		selection.Load(stream, DataFormats.Xaml);
		stream.Dispose();
	}
}

This class makes the (safe) assumption that the two methods will be called only once and in the correct order.

So all that remains is to handle the LivePreview event, inspecting the control being hovered over to see if we can generate a live preview class for it. This sample code comes straight from the demonstration application included with the product. It identifies a color button within the Font Color color picker, a combo box item within the Font Family combo box, and a combo box item within the Font Size combo box. Depending on which of these is being previewed it applies a value to ForegroundProperty, FontFamilyProperty or FontSizeProperty.

private void OnLivePreview(object sender, LivePreviewEventArgs e)
{
	// Check whether the control to be previewed is a ColorButton
	ColorButton colorButton = e.Control as ColorButton;
	if (colorButton != null)
	{
		// Get the color picker to which this button belongs
		ColorPicker colorPicker = ColorPicker.GetColorPicker(colorButton);
		if (colorPicker == colorPickerFontColor)
			e.PreviewObject = new PreviewTextFormatting(textBox.Selection, TextElement.ForegroundProperty,
				new SolidColorBrush(colorButton.Color));
	}

	// Check for a combo box item
	Divelements.SandRibbon.ComboBoxItem comboBoxItem = e.Control as Divelements.SandRibbon.ComboBoxItem;
	if (comboBoxItem != null)
	{
		// Get the combo box to which this item belongs
		Divelements.SandRibbon.ComboBox comboBox = (Divelements.SandRibbon.ComboBox)comboBoxItem.Parent;
		if (comboBox == comboFontSize)
			e.PreviewObject = new PreviewTextFormatting(textBox.Selection,
				TextElement.FontSizeProperty, double.Parse(comboBoxItem.Text));
		else if (comboBox == comboFontFamily)
			e.PreviewObject = new PreviewTextFormatting(textBox.Selection,
				TextElement.FontFamilyProperty, comboBoxItem.FontFamily);
	}
}

Next: Advanced Topics