HypernovaDesktop Components · docs
Binarymission
WPF › Control Visual Sizer › ControlVisualResizer

ControlVisualResizer

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

A container that lets the user resize whatever it holds at run time, by dragging a grip in its bottom-right corner, as a window or a text box with a sizing handle is resized.

public class ControlVisualResizer : ContentControl

Inherits from / implements: ContentControl

Remarks

Wrap any element in it – a chart, a notes box, an image, a panel on a dashboard or design surface – to let the user make it larger or smaller. The content stretches to fill the container by default, so it follows the new size.

How resizing works

The user drags the grip and the container's bottom-right corner follows the pointer, even outside the container's bounds, until the button is released. The new size is set as the container's FrameworkElement.Width and FrameworkElement.Height, so from then on it keeps that size rather than following its parent's layout; its FrameworkElement.MinWidth, FrameworkElement.MaxWidth and the like still apply, which is the way to bound it. A double click on the grip, or a call to ResetSize, clears that size again. ResizeStarted and ResizeCompleted tell you when a drag begins and ends – to save the new layout, for example.

A resize grows the container to the right and downwards, so place it where it can do so: on a Canvas, or with its FrameworkElement.HorizontalAlignment and FrameworkElement.VerticalAlignment set to Left and Top.

The grip

The grip is a 17-pixel square of dots drawn in GripperBrush. IsGripperVisible hides it, IsGripperEnabled leaves it on show but stops it responding, and ResizerStyle replaces its look entirely. The default style gives the container a minimum size of 17 by 17 logical pixels, so the grip always fits.

Shadow

IsDropShadowEnabled gives the container a drop shadow, which helps a resizable panel read as something that can be picked up and changed.

Examples

Two resizable panels on a dashboard canvas; the new sizes are saved when a drag ends.

<Window x:Class="Dashboard.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sizer="clr-namespace:Binarymission.WPF.Controls.Containers;assembly=Binarymission.WPF.Controls.Containers.ControlVisualReSizer"
        Title="Dashboard" Width="900" Height="600">

    <Canvas Background="#F4F6F9">
        <sizer:ControlVisualResizer Canvas.Left="20" Canvas.Top="20" Width="420" Height="260"
                                    MinWidth="200" MinHeight="120" MaxWidth="840"
                                    IsDropShadowEnabled="True" Background="White"
                                    ResizeCompleted="OnPanelResized">
            <Image Source="Images/monthly-sales.png" Stretch="Uniform" />
        </sizer:ControlVisualResizer>

        <sizer:ControlVisualResizer Canvas.Left="460" Canvas.Top="20" Width="280" Height="200"
                                    IsDropShadowEnabled="True" DropShadowDepth="2" DropShadowOpacity="0.4"
                                    Background="White" GripperBrush="SteelBlue">
            <TextBox AcceptsReturn="True" TextWrapping="Wrap" Text="Notes for the board meeting" />
        </sizer:ControlVisualResizer>
    </Canvas>
</Window>

The handler, and a resizer built in code.

using System;
using System.Windows;
using System.Windows.Controls;
using Binarymission.WPF.Controls.Containers;

private void OnPanelResized(object sender, EventArgs e)
{
    ControlVisualResizer panel = (ControlVisualResizer)sender;
    Properties.Settings.Default.SalesPanelSize = new Size(panel.Width, panel.Height);
    Properties.Settings.Default.Save();
}

ControlVisualResizer notes = new ControlVisualResizer
{
    Width = 280,
    Height = 200,
    MinWidth = 160,
    MinHeight = 100,
    IsDropShadowEnabled = true,
    Content = new TextBox { AcceptsReturn = true, TextWrapping = TextWrapping.Wrap }
};
Canvas.SetLeft(notes, 40);
Canvas.SetTop(notes, 300);
dashboardCanvas.Children.Add(notes);

See also

Members at a glance

Properties
DirectionGets or sets which way a drag on the grip resizes the container.
DropShadowDepthGets or sets how far the drop shadow falls below and to the right of the container.
DropShadowOpacityGets or sets how dark the drop shadow is.
EndResizeCommandGets the command that finishes a resize, as the grip does when it is released.
GripperBrushGets or sets the colour of the dots that make up the resize grip.
IsDropShadowEnabledGets or sets whether the container casts a drop shadow.
IsGripperEnabledGets or sets whether the user can resize the container with the grip.
IsGripperVisibleGets or sets whether the resize grip is shown.
ResizerStyleGets or sets the style of the resize grip, to give it a look of your own.
StartResizeCommandGets the command that starts a resize from the current position of the mouse pointer, as the grip does when it is pressed.
UpdateSizeCommandGets the command that resizes the container so that its bottom-right corner follows the mouse pointer's movement since the resize was started.
Methods
OnApplyTemplateConnects the resize grip in the template to the mouse, and applies IsGripperVisible to it.
ResetSizeClears the size the user set by dragging, so the container goes back to the size its content and its parent give it.
Events
ResizeCompletedOccurs when the user releases the grip at the end of a resize.
ResizeStartedOccurs when the user presses the grip to start resizing the container.
Fields
DirectionPropertyIdentifies the Direction dependency property.
DropShadowDepthPropertyIdentifies the DropShadowDepth dependency property.
DropShadowOpacityPropertyIdentifies the DropShadowOpacity dependency property.
GripperBrushPropertyIdentifies the GripperBrush dependency property.
IsDropShadowEnabledPropertyIdentifies the IsDropShadowEnabled dependency property.
IsGripperEnabledPropertyIdentifies the IsGripperEnabled dependency property.
IsGripperVisiblePropertyIdentifies the IsGripperVisible dependency property.
ResizerStylePropertyIdentifies the ResizerStyle dependency property.

Properties

Direction

public Direction Direction

Gets or sets which way a drag on the grip resizes the container.

Value
Direction.SouthEast or Direction.None. The default is Direction.SouthEast: the grip is in the bottom-right corner and resizes the container to the right and downwards.
Remarks

Direction.None leaves the grip on show but a drag does not change the size; it also moves the grip to the bottom-left corner and hides the mouse pointer over it. To stop resizing, IsGripperEnabled or IsGripperVisible is usually the clearer choice.

DropShadowDepth

public double DropShadowDepth

Gets or sets how far the drop shadow falls below and to the right of the container.

Value
A distance in logical pixels (1/96 inch). The default is 4. Negative values are read as 0.
Remarks

Used only while IsDropShadowEnabled is true. The shadow is drawn outside the container's bounds and takes no room in the layout.

See also

DropShadowOpacity

public double DropShadowOpacity

Gets or sets how dark the drop shadow is.

Value
From 0 (invisible) to 1 (solid black). The default is 0.75. Values outside that range are brought within it.
Remarks

Used only while IsDropShadowEnabled is true.

See also

EndResizeCommand static

public static RoutedCommand EndResizeCommand

Gets the command that finishes a resize, as the grip does when it is released.

Value
A routed command handled by every ControlVisualResizer.
Remarks

It raises ResizeCompleted if a resize was in progress, and does nothing otherwise. The command parameter is not used.

See also

GripperBrush

public Brush GripperBrush

Gets or sets the colour of the dots that make up the resize grip.

Value
The default style takes it from the resource keyed ControlVisualResizerThemeResources.ResizeGripTopElementBrushKey: grey, or the skin's secondary text colour while a Binarymission skin is in force. The value registered on the property is null, which draws no grip.
Remarks

Set it on the control for a colour of your own, or redefine the resource key in the application's resources to change every resizer at once. Ignored by a ResizerStyle of your own unless that style binds it.

IsDropShadowEnabled

public bool IsDropShadowEnabled

Gets or sets whether the container casts a drop shadow.

Value
true for a shadow. The default is false.
Remarks

The shadow is set as the container's UIElement.Effect, shaped by DropShadowDepth and DropShadowOpacity. The container manages that property itself: turning the shadow off, or changing its depth or opacity while it is off, sets UIElement.Effect to null, removing any effect of your own. To give the container a different effect, leave the shadow off and set UIElement.Effect after the other properties.

IsGripperEnabled

public bool IsGripperEnabled

Gets or sets whether the user can resize the container with the grip.

Value
true to allow resizing. The default is true.
Remarks

With the property off, the grip stays on show but does not respond to the mouse – useful to lock a layout while still showing that it can be unlocked. To hide the grip as well, use IsGripperVisible.

Example
// Lock every panel on the dashboard while the layout is not being edited.
foreach (ControlVisualResizer panel in dashboardCanvas.Children.OfType<ControlVisualResizer>())
{
    panel.IsGripperEnabled = isEditingLayout;
}
See also

IsGripperVisible

public bool IsGripperVisible

Gets or sets whether the resize grip is shown.

Value
true to show the grip. The default is true.
Remarks

A hidden grip cannot be dragged, so hiding it also stops the user resizing the container. The content does not move into the space the grip leaves, because the grip is drawn over the content's corner.

See also

ResizerStyle

public Style ResizerStyle

Gets or sets the style of the resize grip, to give it a look of your own.

Value
A Style whose target type is ResizeGrip. The default style sets the suite's own grip style: a transparent 17-pixel square with a triangle of dots in GripperBrush in its corner. The value registered on the property is null, which gives the grip the Windows theme's look.
Remarks

The grip's size, position and cursor are set by the container's template and are not taken from this style.

Example
<sizer:ControlVisualResizer.ResizerStyle>
    <Style TargetType="ResizeGrip">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ResizeGrip">
                    <Path Data="M 0,17 L 17,0 L 17,17 Z" Fill="#802B579A" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</sizer:ControlVisualResizer.ResizerStyle>

StartResizeCommand static

public static RoutedCommand StartResizeCommand

Gets the command that starts a resize from the current position of the mouse pointer, as the grip does when it is pressed.

Value
A routed command handled by every ControlVisualResizer.
Remarks

The grip uses these three commands to do its work, and they are public so that a grip of your own, or any element inside the container, can drive a resize the same way. Execute StartResizeCommand when the drag begins, UpdateSizeCommand as the mouse moves and EndResizeCommand when it is released, each with an element inside the container (or the container itself) as the target. Capture the mouse for the length of the drag, as the grip does, so that the moves keep arriving outside the container.

The command parameter must be a FrameworkElement – the element doing the dragging; any other parameter, including null, makes the command throw an InvalidOperationException. The command raises ResizeStarted.

Example
// A custom handle inside the container that resizes it.
handle.MouseLeftButtonDown += (s, e) =>
{
    handle.CaptureMouse();
    ControlVisualResizer.StartResizeCommand.Execute(handle, handle);
};
handle.MouseMove += (s, e) =>
{
    if (handle.IsMouseCaptured) ControlVisualResizer.UpdateSizeCommand.Execute(null, handle);
};
handle.MouseLeftButtonUp += (s, e) =>
{
    ControlVisualResizer.EndResizeCommand.Execute(null, handle);
    handle.ReleaseMouseCapture();
};
See also

UpdateSizeCommand static

public static RoutedCommand UpdateSizeCommand

Gets the command that resizes the container so that its bottom-right corner follows the mouse pointer's movement since the resize was started.

Value
A routed command handled by every ControlVisualResizer.
Remarks

It sets FrameworkElement.Width and FrameworkElement.Height, never below 0, and does nothing unless StartResizeCommand has started a resize. With Direction set to Direction.None it sets them to the size the container had when the resize started. The command parameter is not used.

See also

Methods

OnApplyTemplate

public override void OnApplyTemplate()

Connects the resize grip in the template to the mouse, and applies IsGripperVisible to it.

Remarks

A custom template names its grip PART_ReSizerGrip, and it must be a ResizeGrip. A template without one shows its content and cannot be resized by dragging.

ResetSize

public void ResetSize()

Clears the size the user set by dragging, so the container goes back to the size its content and its parent give it.

Remarks

It clears FrameworkElement.Width and FrameworkElement.Height altogether, including a size set in markup or code before any drag. A double click on the grip does the same. ResizeCompleted is not raised.

Example
// "Reset layout" on the View menu.
foreach (ControlVisualResizer panel in dashboardCanvas.Children.OfType<ControlVisualResizer>())
{
    panel.ResetSize();
}

Events

ResizeCompleted

public event EventHandler ResizeCompleted

Occurs when the user releases the grip at the end of a resize.

Remarks

The new size is in FrameworkElement.Width and FrameworkElement.Height, which makes this the place to save a layout the user has arranged. Also raised when EndResizeCommand ends a resize started from code.

It is not raised by a double click on the grip or by ResetSize, which put the container back to its natural size.

See also

ResizeStarted

public event EventHandler ResizeStarted

Occurs when the user presses the grip to start resizing the container.

Remarks

Raised before the size changes; the container's FrameworkElement.ActualWidth and FrameworkElement.ActualHeight are still the size it started at. Also raised when StartResizeCommand is executed from code.

See also

Fields

DirectionProperty static

public static readonly DependencyProperty DirectionProperty

Identifies the Direction dependency property.

DropShadowDepthProperty static

public static readonly DependencyProperty DropShadowDepthProperty = DependencyProperty.Register( "DropShadowDepth", typeof(double), typeof(ControlVisualResizer), new PropertyMetadata(DefaultShadowDepth, (o, args)

Identifies the DropShadowDepth dependency property.

DropShadowOpacityProperty static

public static readonly DependencyProperty DropShadowOpacityProperty = DependencyProperty.Register( "DropShadowOpacity", typeof(double), typeof(ControlVisualResizer), new PropertyMetadata(DefaultShadowOpacity, (o, args)

Identifies the DropShadowOpacity dependency property.

GripperBrushProperty static

public static readonly DependencyProperty GripperBrushProperty

Identifies the GripperBrush dependency property.

IsDropShadowEnabledProperty static

public static readonly DependencyProperty IsDropShadowEnabledProperty = DependencyProperty.Register( "IsDropShadowEnabled", typeof(bool), typeof(ControlVisualResizer), new PropertyMetadata(default(bool), (o, args)

Identifies the IsDropShadowEnabled dependency property.

IsGripperEnabledProperty static

public static readonly DependencyProperty IsGripperEnabledProperty

Identifies the IsGripperEnabled dependency property.

IsGripperVisibleProperty static

public static readonly DependencyProperty IsGripperVisibleProperty

Identifies the IsGripperVisible dependency property.

ResizerStyleProperty static

public static readonly DependencyProperty ResizerStyleProperty

Identifies the ResizerStyle dependency property.