ControlVisualResizer
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 | |
|---|---|
Direction | Gets or sets which way a drag on the grip resizes the container. |
DropShadowDepth | Gets or sets how far the drop shadow falls below and to the right of the container. |
DropShadowOpacity | Gets or sets how dark the drop shadow is. |
EndResizeCommand | Gets the command that finishes a resize, as the grip does when it is released. |
GripperBrush | Gets or sets the colour of the dots that make up the resize grip. |
IsDropShadowEnabled | Gets or sets whether the container casts a drop shadow. |
IsGripperEnabled | Gets or sets whether the user can resize the container with the grip. |
IsGripperVisible | Gets or sets whether the resize grip is shown. |
ResizerStyle | Gets or sets the style of the resize grip, to give it a look of your own. |
StartResizeCommand | Gets the command that starts a resize from the current position of the mouse pointer, as the grip does when it is pressed. |
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. |
| Methods | |
OnApplyTemplate | Connects the resize grip in the template to the mouse, and applies IsGripperVisible
to it. |
ResetSize | Clears the size the user set by dragging, so the container goes back to the size its content and its parent give it. |
| Events | |
ResizeCompleted | Occurs when the user releases the grip at the end of a resize. |
ResizeStarted | Occurs when the user presses the grip to start resizing the container. |
| Fields | |
DirectionProperty | Identifies the Direction dependency property. |
DropShadowDepthProperty | Identifies the DropShadowDepth dependency property. |
DropShadowOpacityProperty | Identifies the DropShadowOpacity dependency property. |
GripperBrushProperty | Identifies the GripperBrush dependency property. |
IsDropShadowEnabledProperty | Identifies the IsDropShadowEnabled dependency property. |
IsGripperEnabledProperty | Identifies the IsGripperEnabled dependency property. |
IsGripperVisibleProperty | Identifies the IsGripperVisible dependency property. |
ResizerStyleProperty | Identifies the ResizerStyle dependency property. |
Properties
Direction
Gets or sets which way a drag on the grip resizes the container.
- Value
Direction.SouthEastorDirection.None. The default isDirection.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
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 as0.
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
Gets or sets how dark the drop shadow is.
- Value
- From
0(invisible) to1(solid black). The default is0.75. Values outside that range are brought within it.
Remarks
Used only while IsDropShadowEnabled is true.
See also
EndResizeCommand static
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
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 isnull, 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
Gets or sets whether the container casts a drop shadow.
- Value
truefor a shadow. The default isfalse.
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
Gets or sets whether the user can resize the container with the grip.
- Value
trueto allow resizing. The default istrue.
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
Gets or sets whether the resize grip is shown.
- Value
trueto show the grip. The default istrue.
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
Gets or sets the style of the resize grip, to give it a look of your own.
- Value
- A
Stylewhose target type isResizeGrip. The default style sets the suite's own grip style: a transparent 17-pixel square with a triangle of dots inGripperBrushin its corner. The value registered on the property isnull, 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
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
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
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
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
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
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
Identifies the Direction dependency property.
DropShadowDepthProperty static
Identifies the DropShadowDepth dependency property.
DropShadowOpacityProperty static
Identifies the DropShadowOpacity dependency property.
GripperBrushProperty static
Identifies the GripperBrush dependency property.
IsDropShadowEnabledProperty static
Identifies the IsDropShadowEnabled dependency property.
IsGripperEnabledProperty static
Identifies the IsGripperEnabled dependency property.
IsGripperVisibleProperty static
Identifies the IsGripperVisible dependency property.
ResizerStyleProperty static
Identifies the ResizerStyle dependency property.