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

前端 未结 1 2046
借酒劲吻你
借酒劲吻你 2021-01-30 15:24

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

相关标签:
1条回答
  • 2021-01-30 15:57

    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 here enter image description here

    With content inside (Button)

    enter image description here

    Sorry the cursors do not show when using SnipTool

    0 讨论(0)
提交回复
热议问题