Disable Horizontal or Vertical Shape Resizing

In RadDiagram each RadDiagramItem can be resized. This operation is internally implemented by a ResizingService.

In order to learn more about the different Diagramming Services, you can examine the Services article.

In this tutorial we will examine a solution that allows the user to dynamically configure RadDiagramShapes resizing and decide whether to allow horizontal and vertical resizing.

First we will create a sample RadDiagram definition that has two RadDiagramShape objects:

<telerik:RadDiagram x:Name="diagram"> 
    <telerik:RadDiagramShape Geometry="{telerik:FlowChartShape ShapeType=BeginLoopShape}" Position="400 300" /> 
    <telerik:RadDiagramShape Geometry="{telerik:FlowChartShape ShapeType=ExternalDataShape}" Position="500 400" /> 
</telerik:RadDiagram> 

Next, we will add two RadToggleButtons to provide the user with the option to turn on and off the vertical and horizontal resizing of a shape.

<StackPanel Width="200" HorizontalAlignment="Left"> 
    <TextBlock FontSize="16" 
               FontWeight="Bold" 
               Text="Resizing: " /> 
    <telerik:RadToggleButton x:Name="resizeWidth" 
                             Width="130" 
                             Height="30" 
                             Content="CanResizeWidth" 
                             IsChecked="True" /> 
    <telerik:RadToggleButton x:Name="resizeHeight" 
                             Width="130" 
                             Height="30" 
                             Content="CanResizeHeight" 
                             IsChecked="True" /> 
</StackPanel> 

Now that we've defined the content of our view, we can start describing the custom resizing implementation. And as we need to disable a resizing operation based on dynamically set values, we will have to customize the default resizing mechanism. This mechanism is controlled by the ResizingService class which exposes a virtual method that calculates how to change the current size of a shape. Therefore we will start by creating a custom resizing service that derives from the RadDiagram ResizingService and we will override the CalculateNewDelta() method.

public class MyResizing : ResizingService 
{ 
    public MyResizing(RadDiagram owner) 
        : base(owner as IGraphInternal) 
    { 
    } 
 
    protected override Point CalculateNewDelta(Point newPoint) 
    { 
        return base.CalculateNewDelta(newPoint); 
    } 
} 
Public Class MyResizing 
    Inherits ResizingService 
 
    Public Sub New(ByVal owner As RadDiagram) 
        MyBase.New(TryCast(owner, IGraphInternal)) 
 
    End Sub 
 
    Protected Overrides Function CalculateNewDelta(ByVal newPoint As Point) As Point 
        Return MyBase.CalculateNewDelta(newPoint) 
    End Function 
End Class 

Since we added two RadToggleButtons in our view, we need to define two boolean properties to track the checked state of these buttons and use them to control the result of the resizing operation.

public class MyResizing : ResizingService, INotifyPropertyChanged 
{ 
    private bool canResizeHeight; 
    private bool canResizeWidth; 
 
    public MyResizing(RadDiagram owner) 
        : base(owner as IGraphInternal) 
    { 
        //Initialize the boolean properties that will control the availability of the resizing 
        this.CanResizeWidth = true; 
        this.CanResizeHeight = true; 
    } 
 
    public event PropertyChangedEventHandler PropertyChanged; 
 
    public bool CanResizeWidth 
    { 
        get 
        { 
            return this.canResizeWidth; 
        } 
        set 
        { 
            if (this.canResizeWidth != value) 
            { 
                this.canResizeWidth = value; 
                this.OnPropertyChaged("CanResizeWidth"); 
            } 
        } 
    } 
    public bool CanResizeHeight 
    { 
        get 
        { 
            return this.canResizeHeight; 
        } 
        set 
        { 
            if (this.canResizeHeight != value) 
            { 
                this.canResizeHeight = value; 
                this.OnPropertyChaged("CanResizeHeight"); 
            } 
        } 
    } 
 
    protected override Point CalculateNewDelta(Point newPoint) 
    { 
        //calculate the size change using the defaul calulation mechanism 
        var newDelta = base.CalculateNewDelta(newPoint); 
        //use the boolean properties to determine whether to apply any changes in the size of the manipulated item 
        return new Point(this.CanResizeWidth ? newDelta.X : 0, this.CanResizeHeight ? newDelta.Y : 0); 
    } 
 
    private void OnPropertyChaged(string name) 
    { 
        if (this.PropertyChanged != null) 
        { 
            this.PropertyChanged(this, new PropertyChangedEventArgs(name)); 
        } 
    } 
} 
Public Class MyResizing 
    Inherits ResizingService 
    Implements INotifyPropertyChanged 
 
    Private resizeHeight As Boolean 
    Private resizeWidth As Boolean 
 
    Public Sub New(ByVal owner As RadDiagram) 
        MyBase.New(TryCast(owner, IGraphInternal)) 
        'Initialize the boolean properties that will control the availability of the resizing' 
        Me.CanResizeWidth = True 
        Me.CanResizeHeight = True 
    End Sub 
 
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 
 
    Public Property CanResizeWidth() As Boolean 
        Get 
            Return Me.resizeWidth 
        End Get 
        Set(ByVal value As Boolean) 
            If Me.resizeWidth <> value Then 
                Me.resizeWidth = value 
                Me.OnPropertyChaged("CanResizeWidth") 
            End If 
        End Set 
    End Property 
    Public Property CanResizeHeight() As Boolean 
        Get 
            Return Me.resizeHeight 
        End Get 
        Set(ByVal value As Boolean) 
            If Me.resizeHeight <> value Then 
                Me.resizeHeight = value 
                Me.OnPropertyChaged("CanResizeHeight") 
            End If 
        End Set 
    End Property 
 
    Protected Overrides Function CalculateNewDelta(ByVal newPoint As Point) As Point 
        'calculate the size change using the defaul calulation mechanism' 
        Dim newDelta = MyBase.CalculateNewDelta(newPoint) 
        'use the boolean properties to determine whether to apply any changes in the size of the manipulated item' 
        Return New Point(If(Me.CanResizeWidth, newDelta.X, 0), If(Me.CanResizeHeight, newDelta.Y, 0)) 
    End Function 
 
    Private Sub OnPropertyChaged(ByVal name As String) 
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name)) 
    End Sub 
End Class 

Please note that the CalculateNewDelta() method returns a result of type Point. However, this result doesn't describe coordinates of a point, but a delta value representing the change that should be applied on RadDiagramItem(s) size. This delta is calculated based on the resizing direction specified by the resizing thumb being used, the coordinates of the mouse when the resize was initiated, the coordinates of the mouse when the operation was finished and the rotation angle. The X porperty of the calculated result reflects the change in the Width of the manipulated item, while the Y property value reflects the change that has to be applied on the Height of the item. This is why when you override the CalculateNewDelta() method to return a Point with X and Y properties set to 0, you tell RadDiagram that there is no change in the size of the manipulated RadDiagramItem(s).

If you take a look at the custom CalculateNewDelta() method implementation, you can note that the logic is straight-forward. It takes into account the values of the CanResizeWidth and CanResizeHeight properties to decide whether there should be a change in the Width or Height of the manipulated item. If both boolean properties are set to false, then the CalculateNewDelta() method returns a result of Point(0,0) which indicates that there are no changes in the size of the manipulated shape. This way the initiated resizing is ignored and the actual size of the manipulated shape is not changed.

Finally, we need to configure the RadDiagram instance to use our custom resizing service instead of the default ResizingService. This is why we need to create a new instance of the MyResizing class in the code-behind file of our view. Then we need to make sure that the CanResizeWidth and CanResizeHeight properties are used as binding paths for the IsChecked properties of the two RadToggleButtons we defined to control the user ability to resize a shape:

private MyResizing newResizingService; 
 
public Example() 
{ 
    InitializeComponent(); 
 
    this.InitializeNewServices(); 
} 
 
private void InitializeNewServices() 
{ 
    //initialize the newResizingService 
    this.newResizingService = new MyResizing(this.diagram); 
     //create a binding with Path=CanResizeWidth 
    Binding binding = new Binding("CanResizeWidth"); 
    //use the newResizingService as a source of the binding 
    binding.Source = this.newResizingService; 
    binding.Mode = BindingMode.TwoWay; 
    //apply the binding on the resizeWidth RadToggleButton 
    this.resizeWidth.SetBinding(RadToggleButton.IsCheckedProperty, binding); 
 
    //create a binding with Path=CanResizeHeight 
    binding = new Binding("CanResizeHeight"); 
    //use the newResizingService as a source of the binding 
    binding.Source = this.newResizingService; 
    binding.Mode = BindingMode.TwoWay; 
    //apply the binding on the resizeHeight RadToggleButton 
    this.resizeHeight.SetBinding(RadToggleButton.IsCheckedProperty, binding); 
} 
Private newResizingService As MyResizing 
 
Public Sub New() 
    InitializeComponent() 
 
    Me.InitializeNewServices() 
End Sub 
 
Private Sub InitializeNewServices() 
    'initialize the newResizingService' 
    Me.newResizingService = New MyResizing(Me.diagram) 
    'create a binding with Path=CanResizeWidth' 
    Dim binding As New Binding("CanResizeWidth") 
    'use the newResizingService as a source of the binding' 
    binding.Source = Me.newResizingService 
    binding.Mode = BindingMode.TwoWay 
    'apply the binding on the resizeWidth RadToggleButton' 
    Me.resizeWidth.SetBinding(RadToggleButton.IsCheckedProperty, binding) 
 
    'create a binding with Path=CanResizeHeight' 
    binding = New Binding("CanResizeHeight") 
    'use the newResizingService as a source of the binding' 
    binding.Source = Me.newResizingService 
    binding.Mode = BindingMode.TwoWay 
    'apply the binding on the resizeHeight RadToggleButton' 
    Me.resizeHeight.SetBinding(RadToggleButton.IsCheckedProperty, binding) 
End Sub 

And now we can use the newResizingService instance and register it through the ServiceLocator:

public Example() 
{ 
    InitializeComponent(); 
 
    this.InitializeNewServices(); 
    this.diagram.ServiceLocator.Register<IResizingService>(this.newResizingService); 
} 
Public Sub New() 
    InitializeComponent() 
 
    Me.InitializeNewServices()   
    Me.diagram.ServiceLocator.Register(Of IResizingService)(Me.newResizingService) 
End Sub 

If you run the solution now the resizing buttons will be checked thus allowing all resizing operations. raddiagram-howto-custom-resizing-allowed

However, as soon as you uncheck any of the buttons, the related resizing operation will be denied. For instance, if you click the CanResizeWidth button, you will not be able to change the Width of the RadDiagramShapes. And as soon as you also uncheck the CanResizeHeight button, the Height will also be locked.

Find a runnable project of the previous example in the WPF Samples GitHub repository.

See Also

In this article