wpfxamluser-interfaceexpression-blend

Create a Resizable Panel at Runtime


I'm trying to make a grid to be resizable by the user at runtime. I found a quite a few examples, but they all seem to make it a overly-complicated by using adorners etc.

I'd like just to use one simple control in the bottom-right corner, such as a thumb or ResizeGrip, that will enable to user to resize the panel.


Solution

  • You can use a Thumb to calculate the Resize logic and override the Style of a ContentPresenter then you can add a Grid to the ContentPresenter

    Working Example:

    Code:

    namespace WpfApplication12
    {
        /// <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;
            }
        }
    

    }

    Xaml:

    <Window x:Class="WpfApplication12.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication12"
            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}}">
                                <Control x:Name="resizer">
                                    <Control.Style>
                                        <Style TargetType="{x:Type Control}">
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="{x:Type Control}">
                                                        <Grid Margin="-3">
                                                            <local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNWSE" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                                                        </Grid>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </Control.Style>
                                </Control>
                                <ContentPresenter Content="{TemplateBinding Content}"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    
        </Window.Resources>
    
        <Canvas>
            <ContentControl Width="200" Height="100"  Canvas.Left="10" Canvas.Top="10" >
                <Grid Background="Blue">
                    <TextBlock Text="ResizeGrid" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Red" />
                </Grid>
            </ContentControl>
        </Canvas>
    
    </Window>
    

    Result:

    enter image description here enter image description here