HypernovaDesktop Components · docs
Binarymission
WPF › Bubble Control › BubbleControl

BubbleControl

class.NET 6 / 8 / 10.NET Framework 4.8Binarymission.WPF.Controls.CommandVisuals

A content control that answers every click on its content with a ripple: a ring of colour that spreads out from the point clicked and fades away, as a touch screen shows where it was touched.

public class BubbleControl : ContentControl

Inherits from / implements: ContentControl

Remarks

Wrap it round anything – a button, a tile, an image, a whole panel – to give the user an immediate, visible answer to a click. It is especially useful on touch screens and kiosks, in software demonstrations and screen recordings, where the audience needs to see where the presenter clicked, and on large tiles whose own response might otherwise go unnoticed.

How it works

A press of the left mouse button anywhere over the content starts a bubble at the pointer. The bubble grows over 0.55 seconds to a diameter of BubbleExpansionFactor times twice the control's longer side, fading out as it grows, and is clipped to the control's bounds. The click still reaches the content as normal – the control only watches it.

Appearance

The bubble is three concentric rings: BubbleOuterLayerBrush on the outside, BubbleInnerLayerBrush at half the diameter and BubbleChildLayerBrush at a quarter. ShouldRunOnTop chooses whether it is drawn over the content or behind it. The default style gives the control a transparent Control.Background, so the whole of its area answers the pointer, not only the parts the content paints.

Which gestures raise a bubble

Add other routed events – a right-button release, a touch, a stylus tap – to BubbleInvocationEvents. Events that carry a pointer position start the bubble there.

Examples

A grid of dashboard tiles, each wrapped so that a click or a right-click ripples in the company's colours.

<Window x:Class="Dashboard.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cv="clr-namespace:Binarymission.WPF.Controls.CommandVisuals;assembly=Binarymission.WPF.Controls.BubbleControl"
        Title="Sales dashboard" Width="640" Height="360">

    <UniformGrid Columns="2" Margin="12">
        <cv:BubbleControl BubbleExpansionFactor="0.3"
                          BubbleOuterLayerBrush="#552196F3"
                          BubbleInnerLayerBrush="#882196F3"
                          BubbleChildLayerBrush="#FF1565C0">
            <Border Margin="6" Background="#F3F7FC" BorderBrush="#C9D6E6" BorderThickness="1"
                    MouseLeftButtonUp="OnOpenOrders">
                <TextBlock Margin="16" FontSize="18" Text="Open orders: 128" />
            </Border>
        </cv:BubbleControl>

        <cv:BubbleControl BubbleExpansionFactor="0.3">
            <Border Margin="6" Background="#F3F7FC" BorderBrush="#C9D6E6" BorderThickness="1">
                <TextBlock Margin="16" FontSize="18" Text="Overdue invoices: 7" />
            </Border>
        </cv:BubbleControl>
    </UniformGrid>
</Window>

The same in code, with the right mouse button raising a bubble too.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Binarymission.WPF.Controls.CommandVisuals;

BubbleControl tile = new BubbleControl
{
    BubbleExpansionFactor = 0.3,
    BubbleOuterLayerBrush = new SolidColorBrush(Color.FromArgb(0x55, 0x21, 0x96, 0xF3)),
    Content = new TextBlock { Margin = new Thickness(16), FontSize = 18, Text = "Open orders: 128" }
};
tile.BubbleInvocationEvents.Add(UIElement.MouseRightButtonUpEvent);

See also

Members at a glance

Constructors
BubbleControlCreates a bubble control that answers the left mouse button, with its own BubbleInvocationEvents collection.
Properties
BubbleChildLayerBrushGets or sets the colour of the dot at the centre of the bubble, a quarter of the diameter of the outer ring.
BubbleExpansionFactorGets or sets how large the bubble grows, as a proportion of the control's size.
BubbleInnerLayerBrushGets or sets the colour of the bubble's middle ring, half the diameter of the outer one.
BubbleInvocationEventsGets or sets the routed events, besides a press of the left mouse button, that start a bubble.
BubbleOuterLayerBrushGets or sets the colour of the bubble's outer ring – the widest part of the ripple.
ShouldRunOnTopGets or sets whether the bubble is drawn over the content or behind it.
Methods
OnApplyTemplateFinds the parts of the template that draw the bubble, and starts listening for the left mouse button.
Fields
BubbleChildLayerBrushPropertyIdentifies the BubbleChildLayerBrush dependency property.
BubbleExpansionFactorPropertyIdentifies the BubbleExpansionFactor dependency property.
BubbleInnerLayerBrushPropertyIdentifies the BubbleInnerLayerBrush dependency property.
BubbleInvocationEventsPropertyIdentifies the BubbleInvocationEvents dependency property.
BubbleOuterLayerBrushPropertyIdentifies the BubbleOuterLayerBrush dependency property.
ShouldRunOnTopPropertyIdentifies the ShouldRunOnTop dependency property.

Constructors

BubbleControl

public BubbleControl()

Creates a bubble control that answers the left mouse button, with its own BubbleInvocationEvents collection.

Properties

BubbleChildLayerBrush

public Brush BubbleChildLayerBrush

Gets or sets the colour of the dot at the centre of the bubble, a quarter of the diameter of the outer ring.

Value
The default is Brushes.DarkSeaGreen.
See also

BubbleExpansionFactor

public double BubbleExpansionFactor

Gets or sets how large the bubble grows, as a proportion of the control's size.

Value
The bubble's final diameter is this value times twice the longer of the control's actual width and height. The default is 0.14: on a control 200 logical pixels wide the bubble grows to 56 logical pixels.
Remarks

0 turns the bubble off. 0.5 grows it to the control's longer side, which on a square control is enough to cover it; larger values spread past the edges, where the bubble is clipped. The size is worked out at each click, so it follows the control as it is resized.

Example
<!-- A wide, gentle ripple for a large touch tile. -->
<cv:BubbleControl BubbleExpansionFactor="0.4" />

BubbleInnerLayerBrush

public Brush BubbleInnerLayerBrush

Gets or sets the colour of the bubble's middle ring, half the diameter of the outer one.

Value
The default is Brushes.LightSalmon.
See also

BubbleInvocationEvents

public ObservableCollection<RoutedEvent> BubbleInvocationEvents

Gets or sets the routed events, besides a press of the left mouse button, that start a bubble.

Value
A collection of routed events. Each control starts with a collection of its own holding UIElement.MouseLeftButtonDownEvent.
Remarks

Add any routed event raised on or inside the control – for example UIElement.MouseRightButtonUpEvent, UIElement.TouchDownEvent or UIElement.StylusDownEvent. The control listens for it even when the content has already handled it. Events added to or removed from the collection take effect at once, and so does replacing the whole collection; null leaves only the left button.

The left mouse button always starts a bubble: removing UIElement.MouseLeftButtonDownEvent from the collection does not turn it off. Set BubbleExpansionFactor to 0 to stop bubbles altogether.

A mouse button event starts the bubble at the pointer. Any other event replays it at the place, and the size, of the last mouse button press; before the first press it shows nothing.

Example
// Ripple on a right-click as well, for a context-menu tile.
tile.BubbleInvocationEvents.Add(UIElement.MouseRightButtonUpEvent);

BubbleOuterLayerBrush

public Brush BubbleOuterLayerBrush

Gets or sets the colour of the bubble's outer ring – the widest part of the ripple.

Value
The default is Brushes.LightGreen.
Remarks

The whole bubble fades out as it grows, so opaque colours work well; with ShouldRunOnTop on, a partly transparent colour lets the content show through even at the start.

See also

ShouldRunOnTop

public bool ShouldRunOnTop

Gets or sets whether the bubble is drawn over the content or behind it.

Value
true to draw the bubble over the content, where it is always seen; false to draw it behind, where it shows only through the parts of the content that are transparent. The default style sets true; the value registered on the property is false.
Remarks

Drawing behind suits content with an open background, such as text or an icon on a transparent tile: the ripple spreads round the text without covering it. Over an opaque background it cannot be seen at all. The value is read at each click, so a change takes effect at the next one.

Methods

OnApplyTemplate

public override void OnApplyTemplate()

Finds the parts of the template that draw the bubble, and starts listening for the left mouse button.

Remarks

A custom template gives the bubble a Grid named PART_BubbleLayersHost holding a Storyboard resource keyed StoryPlayer, and a Border named PART_BubbleTopLayer for the bubble itself. Every part is optional: a template without them still shows its content and simply draws no bubble.

Fields

BubbleChildLayerBrushProperty static

public static readonly DependencyProperty BubbleChildLayerBrushProperty

Identifies the BubbleChildLayerBrush dependency property.

BubbleExpansionFactorProperty static

public static readonly DependencyProperty BubbleExpansionFactorProperty

Identifies the BubbleExpansionFactor dependency property.

BubbleInnerLayerBrushProperty static

public static readonly DependencyProperty BubbleInnerLayerBrushProperty

Identifies the BubbleInnerLayerBrush dependency property.

BubbleInvocationEventsProperty static

public static readonly DependencyProperty BubbleInvocationEventsProperty = DependencyProperty.Register("BubbleInvocationEvents", typeof(ObservableCollection<RoutedEvent>), typeof(BubbleControl), new PropertyMetadata( null, (o, args)

Identifies the BubbleInvocationEvents dependency property.

BubbleOuterLayerBrushProperty static

public static readonly DependencyProperty BubbleOuterLayerBrushProperty

Identifies the BubbleOuterLayerBrush dependency property.

ShouldRunOnTopProperty static

public static readonly DependencyProperty ShouldRunOnTopProperty

Identifies the ShouldRunOnTop dependency property.