在項(xiàng)目中經(jīng)常會(huì)遇到類(lèi)似如下要求的需求,創(chuàng)建允許自由拖動(dòng)的控件,這樣的需求可以使用WPF的裝飾器Adorner來(lái)實(shí)現(xiàn)。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-671021.html
一、什么是裝飾器?
- Adorner 是一個(gè)抽象類(lèi),所有裝飾器的實(shí)現(xiàn)都需要繼承此類(lèi),比如ThumbBorderAdorner
- AdornerLayer 一個(gè)類(lèi),表示一個(gè)或多個(gè)裝飾元素的裝飾器呈現(xiàn)層
- 利用AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl)函數(shù),來(lái)獲取指定控件是否有裝飾器布局層
- 利用Adorner[] adorners = adornerLayer.GetAdorners(userControl);,來(lái)查看當(dāng)前控件的裝飾器個(gè)數(shù)
- AdornerDecorator 一個(gè)類(lèi),為可視化樹(shù)中的子元素提供AdornerLayer

二、裝飾器的使用場(chǎng)景
- 為現(xiàn)有的元素添加額外的裝飾,如為Border添加8個(gè)裝飾矩形
三、如何創(chuàng)建自定義的裝飾器?
- 創(chuàng)建一個(gè)類(lèi),繼承自Adorner類(lèi)
- 重寫(xiě)此類(lèi)中需要的函數(shù)
- OnRender(DrawingContext drawingContext) 在派生類(lèi)中重寫(xiě),參與由布局系統(tǒng)控制的呈現(xiàn)操作,調(diào)用此方法時(shí),不直接使用此元素的呈現(xiàn)指令,而是將其保留供布局和繪制在以后異步使用,可以使用drawingContext 來(lái)繪制各種形狀以及圖形。
- ArrangeOverride() 為FrameworkElement派生類(lèi)定位子元素并確定大小,在其中調(diào)用Arrange()函數(shù),來(lái)定位子元素
- GetVisualChild() //獲取第幾個(gè)Thumb控件,在構(gòu)造時(shí)使用
- 簡(jiǎn)單的裝飾可以重寫(xiě)OnRender()函數(shù),在其中繪制所需要的裝飾,參照BorderAdorner
- 復(fù)雜一些的如需要可以定義VisualCollection的集合來(lái)存放裝飾器,重寫(xiě)ArrangeOverride和GetVisualChild函數(shù)來(lái)實(shí)現(xiàn),參照ThumbBorderAdorner
四、給控件使用自定義的Adorner
- 添加Adorner
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 }); } }
?
- 移除 Adorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl); if (adornerLayer != null) { Adorner[] adorners = adornerLayer.GetAdorners(userControl); if (adorners != null && adorners.Count() > 0) adornerLayer.Remove(adorners[0]); }
?
五、處理拖拽Thumb時(shí),導(dǎo)致控件范圍超出父級(jí)容器的情況
- 即在添加裝飾器的控件中添加UserControl_SizeChanged()來(lái)處理控件大小和和未知變化
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) { int tempMargin = 1; //MarkRectUserControl控件始終在父級(jí)容器的1個(gè)像素以?xún)?nèi) 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; }
?
六、測(cè)試使用
?
<UserControl x:Class="BlogDemo.Views.AdornerTestUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:BlogDemo.Views" mc:Ignorable="d" Background="White" d:DesignHeight="450" d:DesignWidth="800" FontSize="20" Foreground="Blue" Loaded="UserControl_Loaded" > <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="請(qǐng)拖拽Thumb控件來(lái)改變,控件大小。" 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> </UserControl>
/// <summary> /// AdornerTestUserControl.xaml 的交互邏輯 /// </summary> 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; } }
?
?
源碼地址:https://gitee.com/LiuShuiRuoBing/code_blog文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-671021.html
?
到了這里,關(guān)于WPF-利用裝飾器實(shí)現(xiàn)控件的自由拖動(dòng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!