Luk*_*ler 6 c# wpf events resize
我目前正在开发一个C#WPF应用程序,它包含一个Grid带有控件的全屏,这些控件在运行时动态添加到它.我有代码允许用户在Grid鼠标事件中移动这些控件.我现在想要做的是允许用户也在运行时调整控件的大小(同时保持宽高比).我已经看过各种教程,描述如何使用Canvas(和Thumb控件),但没有Grid.由于我无法Canvas在我的应用程序中使用a ,有没有一种有效的方法在网格上实现它?为了让您了解我的代码是什么样的,我将鼠标事件放在下面:[编辑如下]
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
//Orientation variables:
public static Point _anchorPoint;
public static Point _currentPoint;
private static double _originalTop;
private static double _originalLeft;
private static Point _startPoint;
private static bool _isDown = false;
private static bool _isInDrag = false;
private static bool _isDragging = false;
public static UIElement selectedElement = null;
public static bool elementIsSelected = false;
public static Dictionary<object, TranslateTransform> PointDict = new Dictionary<object, TranslateTransform>();
public static AdornerLayer aLayer;
public MainWindow()
{
InitializeComponent();
}
//Control events:
public static void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) //HUD element left mouse button up
{
if (_isInDrag)
{
var element = sender as FrameworkElement;
element.ReleaseMouseCapture();
_isInDrag = false;
e.Handled = true;
aLayer = AdornerLayer.GetAdornerLayer(selectedElement);
aLayer.Add(new ResizingAdorner(selectedElement));
}
}
public static void HUD_MouseDown(object sender, MouseButtonEventArgs e)
{
if (elementIsSelected)
{
elementIsSelected = false;
_isDown = false;
if (selectedElement != null)
{
aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]);
selectedElement = null;
}
}
if (e.Source != mw.PACSGrid)
{
_isDown = true;
_startPoint = e.GetPosition(mw.PACSGrid);
selectedElement = e.Source as UIElement;
_originalLeft = VisualWorker.GetLeft(selectedElement);
_originalTop = VisualWorker.GetTop(selectedElement);
aLayer = AdornerLayer.GetAdornerLayer(selectedElement);
aLayer.Add(new ResizingAdorner(selectedElement));
elementIsSelected = true;
e.Handled = true;
}
}
public static void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) //HUD element left mouse button down
{
if (elementIsSelected)
{
aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]);
selectedElement = sender as UIElement;
var element = sender as FrameworkElement;
_anchorPoint = e.GetPosition(null);
element.CaptureMouse();
_isInDrag = true;
e.Handled = true;
}
}
public static void Control_MouseMove(object sender, MouseEventArgs e) //Drag & drop HUD element
{
if (_isInDrag) // The user is currently dragging the HUD element...
{
_currentPoint = e.GetPosition(null);
TranslateTransform tt = new TranslateTransform();
bool isMoved = false;
if (PointDict.ContainsKey(sender))
{
tt = PointDict[sender];
isMoved = true;
}
tt.X += _currentPoint.X - _anchorPoint.X;
tt.Y += (_currentPoint.Y - _anchorPoint.Y);
_anchorPoint = _currentPoint;
(sender as UIElement).RenderTransform = tt;
if (isMoved)
{
PointDict.Remove(sender);
}
PointDict.Add(sender, tt);
}
}
}
// Adorner Class:
public class ResizingAdorner : Adorner
{
Thumb topLeft, topRight, bottomLeft, bottomRight;
// To store and manage the adorner's visual children.
VisualCollection visualChildren;
// Initialize the ResizingAdorner.
public ResizingAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
// Call a helper method to initialize the Thumbs
// with a customized cursors.
BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
BuildAdornerCorner(ref topRight, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
// Add handlers for resizing.
bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft);
bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft);
topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight);
}
// Handler for resizing from the bottom-right.
void HandleBottomRight(object sender, DragDeltaEventArgs args)
{
FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
// Ensure that the Width and Height are properly initialized after the resize.
EnforceSize(adornedElement);
// Change the size by the amount the user drags the mouse, as long as it's larger
// than the width or height of an adorner, respectively.
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
}
// Handler for resizing from the top-right.
void HandleTopRight(object sender, DragDeltaEventArgs args)
{
FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
// Ensure that the Width and Height are properly initialized after the resize.
EnforceSize(adornedElement);
// Change the size by the amount the user drags the mouse, as long as it's larger
// than the width or height of an adorner, respectively.
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
//adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
double height_old = adornedElement.Height;
double height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
double top_old = VisualWorker.GetTop(adornedElement);
//double top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
//Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
VisualWorker.SetTop(adornedElement, top_old - (height_new - height_old));
}
// Handler for resizing from the top-left.
void HandleTopLeft(object sender, DragDeltaEventArgs args)
{
FrameworkElement adornedElement = AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
// Ensure that the Width and Height are properly initialized after the resize.
EnforceSize(adornedElement);
// Change the size by the amount the user drags the mouse, as long as it's larger
// than the width or height of an adorner, respectively.
//adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
//adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
double width_old = adornedElement.Width;
double width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
double left_old = VisualWorker.GetLeft(adornedElement);
//double left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
VisualWorker.SetLeft(adornedElement, left_old - (width_new - width_old));
double height_old = adornedElement.Height;
double height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
double top_old = VisualWorker.GetTop(adornedElement);
//double top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
//Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
VisualWorker.SetTop(adornedElement, top_old - (height_new - height_old));
}
// Handler for resizing from the bottom-left.
void HandleBottomLeft(object sender, DragDeltaEventArgs args)
{
FrameworkElement adornedElement = AdornedElement as FrameworkElement;
Thumb hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
// Ensure that the Width and Height are properly initialized after the resize.
EnforceSize(adornedElement);
// Change the size by the amount the user drags the mouse, as long as it's larger
// than the width or height of an adorner, respectively.
//adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
double width_old = adornedElement.Width;
double width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
double left_old = VisualWorker.GetLeft(adornedElement);
//double left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
//Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
VisualWorker.SetLeft(adornedElement, left_old - (width_new - width_old));
}
// Arrange the Adorners.
protected override Size ArrangeOverride(Size finalSize)
{
// desiredWidth and desiredHeight are the width and height of the element that's being adorned.
// These will be used to place the ResizingAdorner at the corners of the adorned element.
double desiredWidth = AdornedElement.DesiredSize.Width;
double desiredHeight = AdornedElement.DesiredSize.Height;
// adornerWidth & adornerHeight are used for placement as well.
double adornerWidth = this.DesiredSize.Width;
double adornerHeight = this.DesiredSize.Height;
topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
// Return the final size.
return finalSize;
}
// Helper method to instantiate the corner Thumbs, set the Cursor property,
// set some appearance properties, and add the elements to the visual tree.
void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
{
if (cornerThumb != null) return;
cornerThumb = new Thumb();
// Set some arbitrary visual characteristics.
cornerThumb.Cursor = customizedCursor;
cornerThumb.Height = cornerThumb.Width = 10;
cornerThumb.Opacity = 1;
cornerThumb.Background = new ImageBrush(new BitmapImage(new Uri(@"pack://application:,,,/Images/Thumb 1.jpg")));
visualChildren.Add(cornerThumb);
}
// This method ensures that the Widths and Heights are initialized. Sizing to content produces
// Width and Height values of Double.NaN. Because this Adorner explicitly resizes, the Width and Height
// need to be set first. It also sets the maximum size of the adorned element.
void EnforceSize(FrameworkElement adornedElement)
{
if (adornedElement.Width.Equals(Double.NaN))
adornedElement.Width = adornedElement.DesiredSize.Width;
if (adornedElement.Height.Equals(Double.NaN))
adornedElement.Height = adornedElement.DesiredSize.Height;
FrameworkElement parent = adornedElement.Parent as FrameworkElement;
if (parent != null)
{
adornedElement.MaxHeight = parent.ActualHeight;
adornedElement.MaxWidth = parent.ActualWidth;
}
}
// Override the VisualChildrenCount and GetVisualChild properties to interface with
// the adorner's visual collection.
protected override int VisualChildrenCount { get { return visualChildren.Count; } }
protected override Visual GetVisualChild(int index) { return visualChildren[index]; }
}
// Canvas alternative class:
public class VisualWorker
{
public static void SetTop(UIElement uie, double top)
{
var frame = uie as FrameworkElement;
frame.Margin = new Thickness(frame.Margin.Left, top, frame.Margin.Right, frame.Margin.Bottom);
}
public static void SetLeft(UIElement uie, double left)
{
var frame = uie as FrameworkElement;
frame.Margin = new Thickness(left, frame.Margin.Top, frame.Margin.Right, frame.Margin.Bottom);
}
public static double GetTop(UIElement uie)
{
return (uie as FrameworkElement).Margin.Top;
}
public static double GetLeft(UIElement uie)
{
return (uie as FrameworkElement).Margin.Left;
}
}
Run Code Online (Sandbox Code Playgroud)
MainWindow.xaml(示例):
<Window x:Name="MW" x:Class="MyProgram.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"
xmlns:local="clr-namespace:MyProgram"
mc:Ignorable="d"
Title="MyProgram" d:DesignHeight="1080" d:DesignWidth="1920" ResizeMode="NoResize" WindowState="Maximized" WindowStyle="None" MouseLeave="HUD_MouseLeave">
<Grid x:Name="MyGrid MouseDown="HUD_MouseDown" />
<Image x:Name="Image1" Source="pic.png" Margin="880,862,0,0" Height="164" Width="162" HorizontalAlignment="Left" VerticalAlignment="Top" MouseLeftButtonDown="Control_MouseLeftButtonDown" MouseLeftButtonUp="Control_MouseLeftButtonUp" MouseMove="Control_MouseMove" />
<TextBox x:Name="Textbox1" Margin="440,560,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" MouseLeftButtonDown="Control_MouseLeftButtonDown" MouseLeftButtonUp="Control_MouseLeftButtonUp" MouseMove="Control_MouseMove" />
Run Code Online (Sandbox Code Playgroud)
编辑:我发现使用TranslateTransform不会更改控件的边距.我需要保证金才能适当改变才能使其发挥作用.
编辑2:现在我添加了[修改]代码,用于调整大小的装饰器(在此处找到).它几乎真的有效.问题是,我正在经历与装饰者的奇怪行为.在我的一个控件上(左上角),所有4个控件都显示在相应的角落中.但我的其他控件只能获得1-2个装饰,并且它们没有正确间隔.这些行为也很陌生.是的,我意识到这是很多代码,但我怀疑这个问题会出现在ResizingAdorner课堂上.
编辑3:为想要复制和粘贴的人添加了"样板"代码.它应该编译没有问题.如果您有任何问题,请告诉我.
编辑4(1/10/2018):仍然没有好的答案.Thumb如果控件的Margin值为0,0 ,则装饰器上的控件似乎只能正确对齐.从该位置移动时,装饰者会从元素中移出.
编辑5(1/15/2018):adorner类最初是为a Canvas而设计的,并且运行它Grid可能会导致问题.我最好的猜测是,这个ArrangeOverride方法因为它而搞砸了(这就是拇指放在它们身上的地方UIElement).
今天,经过一番尝试和错误,我找到了修复该Adorner错误的方法。正如我所发布的,用于调整元素大小的角拇指未与控件正确对齐。原始代码旨在用于Canvas而不是Grid我正在使用的容器上。错误在于方法double中的某些值ArrangeOverride(安排Thumbs)。原来的代码是:
double desiredWidth = AdornedElement.DesiredSize.Width;
double desiredHeight = AdornedElement.DesiredSize.Height;
// adornerWidth & adornerHeight are used for placement as well.
double adornerWidth = this.DesiredSize.Width;
double adornerHeight = this.DesiredSize.Height;
//Arrange method calls below....
Run Code Online (Sandbox Code Playgroud)
...我修改为:
double desiredWidth = (AdornedElement as FrameworkElement).ActualWidth;
double desiredHeight = (AdornedElement as FrameworkElement).ActualHeight;
// adornerWidth & adornerHeight are used for placement as well.
double adornerWidth = (AdornedElement as FrameworkElement).Width;
double adornerHeight = (AdornedElement as FrameworkElement).Height;
//Arrange the thumbs:
topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
Run Code Online (Sandbox Code Playgroud)
似乎专门用于排列s 的desiredWidth和double 变量没有提供控件的实际尺寸。使用带有此更改的代码是有效的,但对于左上角、右上角和左下角装饰器来说仍然很麻烦。我相信我可以调整自己。感谢所有提供反馈的人。desiredHeightThumb