第一节 Grid内控件拖动调整大小(本章)
第二节 Canvas内控件拖动调整大小
第三节 窗口拖动调整大小
第四节 附加属性实现拖动调整大小
第五章 拓展更多调整大小功能
在《C# wpf Canvas中实现控件动态调整大小》中我们实现了Canvas中的控件动态调整大小,由于Grid也是可层叠布局,在Grid中也是可以实现动态调整大小的。
8个点方放置在控件的8个方位上,通过拖动这些点对控件进行拉伸或缩小,示意图如下:
通过装饰器的方式添加8个点在控件上,这样既可以不影响控件布局,又可以自由摆放8点控件。通过重写方法,给装饰添加控件。必要的重写的方法如下面示例所示:
public class GridAdorner : Adorner
{
//获取装饰器的元素个数
protected override Visual GetVisualChild(int index);
//指定装饰器子元素个数
protected override int VisualChildrenCount{get;}
//布局,添加的子元素需要手动布局。
protected override Size ArrangeOverride(Size finalSize);
}
因为Thumb实现拖动比较容易,有相关事件获取拖动距离。在装饰器中定义8个Thumb,对应8个方位点。
示例代码如下:
//4条边
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4个角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
初始化
public GridAdorner(UIElement adornedElement) : base(adornedElement)
{
//初始化thumb
_leftThumb = new Thumb();
_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftThumb.VerticalAlignment = VerticalAlignment.Center;
_leftThumb.Cursor = Cursors.SizeWE;
//其他略...
}
在Thumb的DragDelta事件可以获取拖动距离,根据八个方位的不同计算并修改控件的大小。
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
//1.右侧点HorizontalChange加宽,右边距减HorizontalChange
//2.左侧点HorizontalChange减宽,左边距加HorizontalChange
//3.下侧点VerticalChange加高,下边距减VerticalChange
//4.上侧点VerticalChange减高,上边距加VerticalChange
}
代码如下:
public class GridAdorner : Adorner
{
//4条边
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4个角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
//布局容器,如果不使用布局容器,则需要给上述8个控件布局,实现和Grid布局定位是一样的,会比较繁琐且意义不大。
Grid _grid;
UIElement _adornedElement;
public GridAdorner(UIElement adornedElement) : base(adornedElement)
{
_adornedElement = adornedElement;
//初始化thumb
_leftThumb = new Thumb();
_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftThumb.VerticalAlignment = VerticalAlignment.Center;
_leftThumb.Cursor = Cursors.SizeWE;
_topThumb = new Thumb();
_topThumb.HorizontalAlignment = HorizontalAlignment.Center;
_topThumb.VerticalAlignment = VerticalAlignment.Top;
_topThumb.Cursor = Cursors.SizeNS;
_rightThumb = new Thumb();
_rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightThumb.VerticalAlignment = VerticalAlignment.Center;
_rightThumb.Cursor = Cursors.SizeWE;
_bottomThumb = new Thumb();
_bottomThumb.HorizontalAlignment = HorizontalAlignment.Center;
_bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_bottomThumb.Cursor = Cursors.SizeNS;
_lefTopThumb = new Thumb();
_lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
_lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
_lefTopThumb.Cursor = Cursors.SizeNWSE;
_rightTopThumb = new Thumb();
_rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
_rightTopThumb.Cursor = Cursors.SizeNESW;
_rightBottomThumb = new Thumb();
_rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_rightBottomThumb.Cursor = Cursors.SizeNWSE;
_leftbottomThumb = new Thumb();
_leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_leftbottomThumb.Cursor = Cursors.SizeNESW;
_grid = new Grid();
_grid.Children.Add(_leftThumb);
_grid.Children.Add(_topThumb);
_grid.Children.Add(_rightThumb);
_grid.Children.Add(_bottomThumb);
_grid.Children.Add(_lefTopThumb);
_grid.Children.Add(_rightTopThumb);
_grid.Children.Add(_rightBottomThumb);
_grid.Children.Add(_leftbottomThumb);
AddVisualChild(_grid);
foreach (Thumb thumb in _grid.Children)
{
thumb.Width = 16;
thumb.Height = 16;
thumb.Background = Brushes.Green;
thumb.Template = new ControlTemplate(typeof(Thumb))
{
VisualTree = GetFactory(new SolidColorBrush(Colors.White))
};
thumb.DragDelta += Thumb_DragDelta;
}
}
protected override Visual GetVisualChild(int index)
{
return _grid;
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
//直接给grid布局,grid内部的thumb会自动布局。
_grid.Arrange(new Rect(new Point(-_leftThumb.Width / 2, -_leftThumb.Height / 2), new Size(finalSize.Width + _leftThumb.Width, finalSize.Height + _leftThumb.Height)));
return finalSize;
}
//拖动逻辑
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var c = _adornedElement as FrameworkElement;
var thumb = sender as FrameworkElement;
double left, top, right, bottom, width, height;
if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
{
right = c.Margin.Right;
left = c.Margin.Left + e.HorizontalChange;
width =(double.IsNaN(c.Width)?c.ActualWidth:c.Width)- e.HorizontalChange;
}
else
{
left = c.Margin.Left;
right = c.Margin.Right - e.HorizontalChange;
width = (double.IsNaN(c.Width) ? c.ActualWidth : c.Width )+ e.HorizontalChange;
}
if (thumb.VerticalAlignment == VerticalAlignment.Top)
{
bottom = c.Margin.Bottom;
top = c.Margin.Top + e.VerticalChange;
height = (double.IsNaN(c.Height) ? c.ActualHeight : c.Height) - e.VerticalChange;
}
else
{
top = c.Margin.Top;
bottom = c.Margin.Bottom - e.VerticalChange;
height = (double.IsNaN(c.Height) ? c.ActualHeight : c.Height )+ e.VerticalChange;
}
if (thumb.HorizontalAlignment != HorizontalAlignment.Center)
{
if (width >= 0)
{
c.Margin = new Thickness(left, c.Margin.Top, right, c.Margin.Bottom);
c.Width = width;
}
}
if (thumb.VerticalAlignment != VerticalAlignment.Center)
{
if (height >= 0)
{
c.Margin = new Thickness(c.Margin.Left, top, c.Margin.Right, bottom);
c.Height = height;
}
}
}
//thumb的样式
FrameworkElementFactory GetFactory(Brush back)
{
var fef = new FrameworkElementFactory(typeof(Ellipse));
fef.SetValue(Ellipse.FillProperty, back);
fef.SetValue(Ellipse.StrokeProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")));
fef.SetValue(Ellipse.StrokeThicknessProperty, (double)2);
return fef;
}
}
示例代码如下:
xaml
<Grid>
<Border x:Name="border" Width="200" Height="200" Background="Gray" >Border>
Grid>
在窗口或控件的Loaded事件中添加装饰器:
cs
private void window_Loaded(object sender, RoutedEventArgs e)
{
var layer = AdornerLayer.GetAdornerLayer(border);
layer.Add(new GridAdorner(border));
}
效果预览:
以上就是今天要讲的内容,本文讲述了Grid中控件缩放的方法与实现,与Canvas的实现大部分是相同的,唯一的区别就是设置Margin,总得来说还是比较容易实现的,最终呈现的效果也是比较不错的。