在项目中经常会遇到类似如下要求的需求,创建允许自由拖动的控件,这样的需求可以使用WPF的装饰器Adorner来实现。
装饰器是一种特殊类型的FrameworkElement,装饰器始终呈现在被装饰元素的顶部,用于向用户提供可视化提示。装饰器可以在不改变原有控件结构的基础上,将功能点增加到元素中或元素上提供视觉效果等,如WPF的光标效果,焦点效果等都是通过装饰器来实现的。
装饰器是一个始终位于装饰元素或装饰元素集合顶部的呈现图层,其呈现独立与它所绑定的UIElement,WPF中的装饰器是在一个单独的曾AnornerLayer上进行绘制的,该层位于普通控件元素之上,而且允许多个AdornerLayer进行叠加,当加入AdornerLayer层后,Adorner会默认使用其所装饰元素的左上角作为原点进行定位。
Adorner 是一个抽象类,所有装饰器的实现都需要继承此类,比如ThumbBorderAdorner
AdornerLayer 一个类,表示一个或多个装饰元素的装饰器呈现层
利用AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl)函数,来获取指定控件是否有装饰器布局层
利用Adorner[] adorners = adornerLayer.GetAdorners(userControl);,来查看当前控件的装饰器个数
AdornerDecorator 一个类,为可视化树中的子元素提供AdornerLayer
创建一个类,继承自Adorner类
重写此类中需要的函数
OnRender(DrawingContext drawingContext) 在派生类中重写,参与由布局系统控制的呈现操作,调用此方法时,不直接使用此元素的呈现指令,而是将其保留供布局和绘制在以后异步使用,可以使用drawingContext 来绘制各种形状以及图形。
ArrangeOverride() 为FrameworkElement派生类定位子元素并确定大小,在其中调用Arrange()函数,来定位子元素
GetVisualChild() //获取第几个Thumb控件,在构造时使用
简单的装饰可以重写OnRender()函数,在其中绘制所需要的装饰,参照BorderAdorner
复杂一些的如需要可以定义VisualCollection的集合来存放装饰器,重写ArrangeOverride和GetVisualChild函数来实现,参照ThumbBorderAdorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl);
if (adornerLayer != null)
{
Adorner[] adorners = adornerLayer.GetAdorners(userControl);
if (adorners == null || adorners.Count() == 0)
{
adornerLayer.Add(new ThumbBorderAdorner(userControl)
{
DragCompletedAction = ThumbBorderAdornerDragCompletedActionFunc
});
}
}
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl);
if (adornerLayer != null)
{
Adorner[] adorners = adornerLayer.GetAdorners(userControl);
if (adorners != null && adorners.Count() > 0)
adornerLayer.Remove(adorners[0]);
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
int tempMargin = 1; //MarkRectUserControl控件始终在父级容器的1个像素以内
double left = Canvas.GetLeft(this);
if (left < tempMargin)
{
left = tempMargin;
Canvas.SetLeft(this, left);
}
double top = Canvas.GetTop(this);
if (top < tempMargin)
{
top = tempMargin;
Canvas.SetTop(this, top);
}
if (left + this.ActualWidth > canvasParent.ActualWidth - tempMargin)
this.Width = canvasParent.ActualWidth - tempMargin - left;
if (top + this.ActualHeight > canvasParent.ActualHeight - tempMargin)
this.Height = canvasParent.ActualHeight - tempMargin - top;
}
<TextBlock Text="请拖拽Thumb控件来改变,控件大小。" HorizontalAlignment="Center" Margin="10"/>
<Canvas x:Name="Canvas\_Main" Grid.Row="1">
<Border x:Name="Border\_Text" Canvas.Left="200" Canvas.Top="100" Width="200" Height="100" BorderThickness="2" BorderBrush="Green" SizeChanged="Border\_Text\_SizeChanged"/>
</Canvas>
</Grid>
///
public partial class AdornerTestUserControl : UserControl
{
public AdornerTestUserControl()
{
InitializeComponent();
}
private void UserControl\_Loaded(object sender, RoutedEventArgs e)
{
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(Border\_Text);
if (adornerLayer != null)
{
Adorner\[\] adorners = adornerLayer.GetAdorners(Border\_Text);
if (adorners == null || adorners.Count() == 0)
{
adornerLayer.Add(new ThumbBorderAdorner(Border\_Text));
}
}
}
private void Border\_Text\_SizeChanged(object sender, SizeChangedEventArgs e)
{
int tempMargin = 100;
double left = Canvas.GetLeft(Border\_Text);
if (left < tempMargin)
{
left = tempMargin;
Canvas.SetLeft(Border\_Text, left);
}
double top = Canvas.GetTop(Border\_Text);
if (top < tempMargin)
{
top = tempMargin;
Canvas.SetTop(Border\_Text, top);
}
if (Border\_Text.ActualWidth < tempMargin)
Border\_Text.Width = tempMargin;
if (Border\_Text.ActualHeight < tempMargin)
Border\_Text.Height = tempMargin;
if (left + Border\_Text.ActualWidth > Canvas\_Main.ActualWidth - tempMargin)
Border\_Text.Width = Canvas\_Main.ActualWidth - tempMargin - left;
if (top + Border\_Text.ActualHeight > Canvas\_Main.ActualHeight - tempMargin)
Border\_Text.Height = Canvas\_Main.ActualHeight - tempMargin - top;
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章