Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a Thumb control sizable using the mouse to drag an edge

I need a thumb control that can be sized using a mouse. When the user hovers the mouse over one of the ends a size cursor should be displayed and when the user clicks and drags the end of the control it will be re-sized.

How can that be achieved?

like image 367
user1401827 Avatar asked Apr 01 '13 16:04

user1401827


People also ask

How do I use the thumb control to move controls?

The Thumb control provides drag functionality that can be used to move or resize controls by monitoring the DragStarted, DragDelta and DragCompleted events of the Thumb. The user begins a drag operation by pressing the left mouse button when the mouse pointer is paused on the Thumb control.

How do you use the drag command on a mouse?

The user begins a drag operation by pressing the left mouse button when the mouse pointer is paused on the Thumb control. The drag operation continues as long as the left mouse button remains pressed. During the drag operation, the DragDelta can occur more than once.

How do I Make my Mouse easier to use in Windows 10?

Clicking the Start button, click Control Panel, click Ease of Access, click Ease of Access Center, and then click Make the mouse easier to use. Select the options that you want to use: Change the color and size of mouse pointers. You can use these options to make the mouse pointer larger, or change the color to make it easier to see.

How to enable mouse gestures in your browser?

Another browser that integrates mouse gestures and which deserves to take more market share away from the big names is Vivaldi. You can find the mouse gestures setting by clicking the Settings button (the cog icon, bottom left): Choose Mouse and then check the Allow Gestures box to enable the feature.


1 Answers

Here is one I made a while ago, it allows Move and Resize, but you can remove the Move logic and it should work fine (the style is still a bit messy, but it works pretty well)

Its based on ContentControl so you can add any Element inside and Move/Resize on a Canvas, It uses 3 Adorners, one for Resize, one for Move and one to display information (current size)

Here is a full working example if you want to test/use/modify/improve :)

Code:

namespace WpfApplication21
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class ResizeThumb : Thumb
    {
        public ResizeThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
        }

        private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control designerItem = this.DataContext as Control;

            if (designerItem != null)
            {
                double deltaVertical, deltaHorizontal;

                switch (VerticalAlignment)
                {
                    case VerticalAlignment.Bottom:
                        deltaVertical = Math.Min(-e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
                        designerItem.Height -= deltaVertical;
                        break;
                    case VerticalAlignment.Top:
                        deltaVertical = Math.Min(e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
                        Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical);
                        designerItem.Height -= deltaVertical;
                        break;
                    default:
                        break;
                }

                switch (HorizontalAlignment)
                {
                    case HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min(e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
                        Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal);
                        designerItem.Width -= deltaHorizontal;
                        break;
                    case HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min(-e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
                        designerItem.Width -= deltaHorizontal;
                        break;
                    default:
                        break;
                }
            }

            e.Handled = true;
        }
    }


    public class MoveThumb : Thumb
    {
        public MoveThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
        }

        private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control designerItem = this.DataContext as Control;

            if (designerItem != null)
            {
                double left = Canvas.GetLeft(designerItem);
                double top = Canvas.GetTop(designerItem);

                Canvas.SetLeft(designerItem, left + e.HorizontalChange);
                Canvas.SetTop(designerItem, top + e.VerticalChange);
            }
        }
    }

    public class SizeAdorner : Adorner
    {
        private Control chrome;
        private VisualCollection visuals;
        private ContentControl designerItem;

        protected override int VisualChildrenCount
        {
            get
            {
                return this.visuals.Count;
            }
        }

        public SizeAdorner(ContentControl designerItem)
            : base(designerItem)
        {
            this.SnapsToDevicePixels = true;
            this.designerItem = designerItem;
            this.chrome = new Control();
            this.chrome.DataContext = designerItem;
            this.visuals = new VisualCollection(this);
            this.visuals.Add(this.chrome);
        }

        protected override Visual GetVisualChild(int index)
        {
            return this.visuals[index];
        }

        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            this.chrome.Arrange(new Rect(new Point(0.0, 0.0), arrangeBounds));
            return arrangeBounds;
        }
    }
}

Xaml:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication21"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <Style TargetType="{x:Type ContentControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ContentControl}">
                        <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                            <local:MoveThumb Cursor="SizeAll">
                                <local:MoveThumb.Style>
                                    <Style TargetType="{x:Type local:MoveThumb}">
                                        <Setter Property="Template">
                                            <Setter.Value>
                                                <ControlTemplate TargetType="{x:Type local:MoveThumb}">
                                                    <Rectangle Fill="Transparent" />
                                                </ControlTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </Style>
                                </local:MoveThumb.Style>
                            </local:MoveThumb>
                            <Control x:Name="resizer">
                                <Control.Style>
                                    <Style TargetType="{x:Type Control}">
                                        <Setter Property="Template">
                                            <Setter.Value>
                                                <ControlTemplate TargetType="{x:Type Control}">
                                                    <Grid>
                                                        <Grid Opacity="0" Margin="-3">
                                                            <local:ResizeThumb Height="3" Cursor="SizeNS" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
                                                            <local:ResizeThumb Width="3" Cursor="SizeWE" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
                                                            <local:ResizeThumb Width="3" Cursor="SizeWE" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
                                                            <local:ResizeThumb Height="3" Cursor="SizeNS" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
                                                            <local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNWSE" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                                                            <local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNESW" VerticalAlignment="Top" HorizontalAlignment="Right"/>
                                                            <local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNESW" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
                                                            <local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNWSE" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                                                        </Grid>
                                                        <Grid IsHitTestVisible="False" Opacity="1" Margin="-3">
                                                            <Grid.Resources>
                                                                <Style TargetType="{x:Type Ellipse}">
                                                                    <Setter Property="SnapsToDevicePixels" Value="true" />
                                                                    <Setter Property="Stroke" Value="#FFC8C8C8" />
                                                                    <Setter Property="StrokeThickness" Value=".5" />
                                                                    <Setter Property="Width" Value="7" />
                                                                    <Setter Property="Height" Value="7" />
                                                                    <Setter Property="Margin" Value="-2" />
                                                                    <Setter Property="Fill" Value="Silver" />
                                                                </Style>
                                                            </Grid.Resources>
                                                            <Rectangle SnapsToDevicePixels="True" StrokeThickness="1" Margin="1" Stroke="Black"  StrokeDashArray="4 4"/>
                                                            <Ellipse  HorizontalAlignment="Left" VerticalAlignment="Top"/>
                                                            <Ellipse  HorizontalAlignment="Right" VerticalAlignment="Top"/>
                                                            <Ellipse HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
                                                            <Ellipse  HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
                                                        </Grid>
                                                    </Grid>
                                                </ControlTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </Style>
                                </Control.Style>
                            </Control>
                            <Grid x:Name="sizeInfo" SnapsToDevicePixels="True">
                                <Path Stroke="Red" StrokeThickness="1" Height="10" VerticalAlignment="Bottom" Margin="-2,0,-2,-15" Stretch="Fill" Data="M0,0 0,10 M 0,5 100,5 M 100,0 100,10"/>
                                <TextBlock Text="{Binding Width}" Background="White" Padding="3,0,3,0" Foreground="Red" Margin="0,0,0,-18" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
                                <Path Stroke="Red" StrokeThickness="1" Width="10" HorizontalAlignment="Right" Margin="0,-2,-15,-2" Stretch="Fill" Data="M5,0 5,100 M 0,0 10,0 M 0,100 10,100"/>
                                <TextBlock Text="{Binding Height}" Background="White" Foreground="Red" Padding="3,0,3,0" Margin="0,0,-18,0" HorizontalAlignment="Right" VerticalAlignment="Center">
                                    <TextBlock.LayoutTransform>
                                        <RotateTransform Angle="90" CenterX="1" CenterY="0.5"/>
                                    </TextBlock.LayoutTransform>
                                </TextBlock>
                            </Grid>
                            <ContentPresenter Content="{TemplateBinding Content}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger  Property="IsMouseOver" Value="True">
                                <Setter TargetName="sizeInfo" Property="Visibility" Value="Visible" />
                            </Trigger>
                            <Trigger  Property="IsMouseOver" Value="False">
                                <Setter TargetName="sizeInfo" Property="Visibility" Value="Hidden" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>

    <Canvas>
        <ContentControl Width="183" Height="110"  Canvas.Left="166" Canvas.Top="50" />
    </Canvas>
</Window>

Result:

enter image description hereenter image description here

With content inside (Button)

enter image description here

Sorry the cursors do not show when using SnipTool

like image 61
sa_ddam213 Avatar answered Sep 28 '22 12:09

sa_ddam213