Я создал простой элемент оформления для элемента TextBlock, который позволяет пользователю изменять его размер. Вы можете изменить размер в четырех углах блока, то есть два размера изменяются одновременно (верхний левый большой палец, верхний правый большой палец, нижний левый большой палец, нижний правый большой палец). Все работает хорошо, вы можете увидеть это на первом GIF:
Также я хочу добавить возможность пропорционального изменения размера с нажатой клавишей Shift вниз. Результат этого вы можете увидеть на втором gif:
Как видите, верхний левый и нижний правый большой палец позволяют вам правильно изменить размеры. Тем не менее, два других элемента большого пальца не работают, я не понимаю, как это было сделано.
XAML:
<Window x:Class="BagControlResize.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas x:Name="canvas">
<TextBlock x:Name="testBlock" Canvas.Left="250" Canvas.Top="120" Width="300" Height="200" Background="Green"/>
</Canvas>
</Window>
CREATE ADORNER:
using System.Windows;
using System.Windows.Documents;
namespace BagControlResize
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += (sender, e) =>
{
var adorner = AdornerLayer.GetAdornerLayer(canvas);
adorner.Add(new TextBlockAdorner(testBlock));
};
}
}
}
ADORNER:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace BagControlResize
{
public class TextBlockAdorner : Adorner
{
private double angle = 0.0;
private Point transformOrigin = new Point(0, 0);
private TextBlock childElement;
private VisualCollection visualChilderns;
private Thumb leftTop, rightTop, leftBottom, rightBottom;
public TextBlockAdorner(UIElement element) : base(element)
{
visualChilderns = new VisualCollection(this);
childElement = element as TextBlock;
CreateThumbPart(ref leftTop);
leftTop.DragDelta += (sender, e) =>
{
double hor = e.HorizontalChange;
double vert = e.VerticalChange;
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
double _max = hor > vert ? hor : vert;
hor = _max;
vert = _max;
}
ResizeX(hor);
ResizeY(vert);
e.Handled = true;
};
CreateThumbPart(ref rightTop);
rightTop.DragDelta += (sender, e) =>
{
double hor = e.HorizontalChange;
double vert = e.VerticalChange;
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
// THIS: NO WORKED
double _max = Math.Abs(hor) > Math.Abs(vert) ? Math.Abs(hor) : Math.Abs(vert);
if (hor >= 0 && vert <= 0)
{
hor = _max;
vert = -_max;
}
else
{
hor = -_max;
vert = _max;
}
}
ResizeWidth(hor);
ResizeY(vert);
e.Handled = true;
};
CreateThumbPart(ref leftBottom);
leftBottom.DragDelta += (sender, e) =>
{
double hor = e.HorizontalChange;
double vert = e.VerticalChange;
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
// THIS: NO WORKED
double _max = Math.Abs(hor) > Math.Abs(vert) ? Math.Abs(hor) : Math.Abs(vert);
if (hor <= 0 && vert >= 0)
{
hor = -_max;
vert = _max;
}
else
{
hor = _max;
vert = -_max;
}
}
ResizeX(hor);
ResizeHeight(vert);
e.Handled = true;
};
CreateThumbPart(ref rightBottom);
rightBottom.DragDelta += (sender, e) =>
{
double hor = e.HorizontalChange;
double vert = e.VerticalChange;
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
double _max = hor > vert ? hor : vert;
hor = _max;
vert = _max;
}
ResizeWidth(hor);
ResizeHeight(vert);
e.Handled = true;
};
}
private void ResizeWidth(double e)
{
double deltaHorizontal = Math.Min(-e, childElement.ActualWidth - childElement.MinWidth);
Canvas.SetTop(childElement, Canvas.GetTop(childElement) - transformOrigin.X * deltaHorizontal * Math.Sin(angle));
Canvas.SetLeft(childElement, Canvas.GetLeft(childElement) + (deltaHorizontal * transformOrigin.X * (1 - Math.Cos(angle))));
childElement.Width -= deltaHorizontal;
}
private void ResizeX(double e)
{
double deltaHorizontal = Math.Min(e, childElement.ActualWidth - childElement.MinWidth);
Canvas.SetTop(childElement, Canvas.GetTop(childElement) + deltaHorizontal * Math.Sin(angle) - transformOrigin.X * deltaHorizontal * Math.Sin(angle));
Canvas.SetLeft(childElement, Canvas.GetLeft(childElement) + deltaHorizontal * Math.Cos(angle) + (transformOrigin.X * deltaHorizontal * (1 - Math.Cos(angle))));
childElement.Width -= deltaHorizontal;
}
private void ResizeHeight(double e)
{
double deltaVertical = Math.Min(-e, childElement.ActualHeight - childElement.MinHeight);
Canvas.SetTop(childElement, Canvas.GetTop(childElement) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle))));
Canvas.SetLeft(childElement, Canvas.GetLeft(childElement) - deltaVertical * transformOrigin.Y * Math.Sin(-angle));
childElement.Height -= deltaVertical;
}
private void ResizeY(double e)
{
double deltaVertical = Math.Min(e, childElement.ActualHeight - childElement.MinHeight);
Canvas.SetTop(childElement, Canvas.GetTop(childElement) + deltaVertical * Math.Cos(-angle) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle))));
Canvas.SetLeft(childElement, Canvas.GetLeft(childElement) + deltaVertical * Math.Sin(-angle) - (transformOrigin.Y * deltaVertical * Math.Sin(-angle)));
childElement.Height -= deltaVertical;
}
public void CreateThumbPart(ref Thumb cornerThumb)
{
cornerThumb = new Thumb { Width = 25, Height = 25, Background= Brushes.Black };
visualChilderns.Add(cornerThumb);
}
public void EnforceSize(FrameworkElement element)
{
if (element.Width.Equals(Double.NaN))
element.Width = element.DesiredSize.Width;
if (element.Height.Equals(Double.NaN))
element.Height = element.DesiredSize.Height;
FrameworkElement parent = element.Parent as FrameworkElement;
if (parent != null)
{
element.MaxHeight = parent.ActualHeight;
element.MaxWidth = parent.ActualWidth;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
base.ArrangeOverride(finalSize);
double desireWidth = AdornedElement.DesiredSize.Width;
double desireHeight = AdornedElement.DesiredSize.Height;
double adornerWidth = this.DesiredSize.Width;
double adornerHeight = this.DesiredSize.Height;
leftTop.Arrange(new Rect(-adornerWidth / 2 - 15, -adornerHeight / 2 - 15, adornerWidth, adornerHeight));
rightTop.Arrange(new Rect(desireWidth - adornerWidth / 2 + 15, -adornerHeight / 2 - 15, adornerWidth, adornerHeight));
leftBottom.Arrange(new Rect(-adornerWidth / 2 - 15, desireHeight - adornerHeight / 2 + 15, adornerWidth, adornerHeight));
rightBottom.Arrange(new Rect(desireWidth - adornerWidth / 2 + 15, desireHeight - adornerHeight / 2 + 15, adornerWidth, adornerHeight));
return finalSize;
}
protected override int VisualChildrenCount => visualChilderns.Count;
protected override Visual GetVisualChild(int index) => visualChilderns[index];
protected override void OnRender(DrawingContext drawingContext) => base.OnRender(drawingContext);
}
}
Я показываю минимум самодостаточного примера, чтобы вы могли точно видеть, что я делаю. Код легко компилируется. Я отметил в коде два места, где я застрял.
Спасибо
UPD 1: