淺談WPF之控件拖拽與拖動

使用過office的visio軟件畫圖的小伙伴都知道,畫圖軟件分為兩部分,左側圖形庫,存放各種圖標,右側是一個畫布,將左側圖形庫的圖標控件拖拽到右側畫布,就會生成一個新的控件,并且可以自由拖動。那如何在WPF程序中,實現類似的功能呢?今天就以一個簡單的小例子,簡述如何在WPF中實現控件的拖拽和拖動,僅供學習分享使用,如有不足之處,還請指正。

涉及知識點

WPF控件的拖拽與拖動,主要涉及知識點如下所示:

  • 容器布局,本示例采用左右布局,主容器采用Grid并分成兩列進行布局,左側圖標庫采用UniformGrid布局,右側畫布采用Canvas布局。
  • 控件拖拽,當圖標庫中的圖標控件被鼠標按下時,通過調用 DragDrop.DoDragDrop方法實現拖拽功能,并且設置畫布的AllowDrop屬性為true,并觸發拖拽松開事件
  • 控件拖動,當圖標庫中的圖標拖拽到新畫布容器后,就會生成一個新的控件,通過屬性按下事件,鼠標移動事件,鼠標升起事件,來實現控件的拖動

實現步驟

1. 頁面布局

根據布局說明,頁面分為左右兩部分【Grid容器】,左側圖標庫【UniformGrid】,右側畫布【Canvas】,如下所示:

<Window x:Class="DemoDragAndDrop.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:DemoDragAndDrop"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding WinLoadedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/></i:EventTrigger></i:Interaction.Triggers><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"></ColumnDefinition><ColumnDefinition Width="*"></ColumnDefinition></Grid.ColumnDefinitions><Border Grid.Column="0" BorderBrush="LightGray" BorderThickness="1"></Border><Border Grid.Column="1" BorderBrush="LightGray" BorderThickness="1"></Border><UniformGrid Grid.Column="0" Columns="2" VerticalAlignment="Top"><UniformGrid.Resources><Style TargetType="TextBlock"><Setter Property="Width" Value="100"></Setter><Setter Property="Height" Value="40"></Setter><Setter Property="FontSize" Value="18"></Setter><Setter Property="TextAlignment" Value="Center"></Setter><Setter Property="Padding" Value="10"></Setter><Setter Property="Margin" Value="5"></Setter><Setter Property="Background" Value="Blue"></Setter><Setter Property="FontWeight" Value="Bold"></Setter><Setter Property="Foreground" Value="White"></Setter></Style></UniformGrid.Resources><TextBlock Text="文本" Tag="Text"><i:Interaction.Triggers><i:EventTrigger EventName="MouseLeftButtonDown"><i:InvokeCommandAction Command="{Binding IconMouseLeftDownCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBlock}}"/></i:EventTrigger></i:Interaction.Triggers></TextBlock><TextBlock Text="按鈕" Tag="Button"><i:Interaction.Triggers><i:EventTrigger EventName="MouseLeftButtonDown"><i:InvokeCommandAction Command="{Binding IconMouseLeftDownCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBlock}}"/></i:EventTrigger></i:Interaction.Triggers></TextBlock><TextBlock Text="單選按鈕"></TextBlock><TextBlock Text="復選按鈕"></TextBlock><TextBlock Text="圓形"></TextBlock><TextBlock Text="長方形"></TextBlock><TextBlock Text="直線"></TextBlock><TextBlock Text="三角形"></TextBlock></UniformGrid><Canvas x:Name="container" Grid.Column="1" AllowDrop="True" Background="White"><i:Interaction.Triggers><i:EventTrigger EventName="Drop"><i:InvokeCommandAction Command="{Binding CanvasDropCommand}" PassEventArgsToCommand="True"/></i:EventTrigger></i:Interaction.Triggers></Canvas></Grid>
</Window>

?

注意,在頁面布局中,為圖標庫中的圖標綁定了MouseLeftButtonDown事件命令,當鼠標左鍵按下時觸發對應的事件,并開始拖拽。如下所示:

private ICommand  iconMouseLeftDownCommand;public ICommand IconMouseLeftDownCommand
{get {if (iconMouseLeftDownCommand == null){iconMouseLeftDownCommand = new RelayCommand<object>(IconMouseLeftDown);}return iconMouseLeftDownCommand; }
}private void IconMouseLeftDown(object sender)
{var tag = (sender as TextBlock)?.Tag?.ToString();if (tag == null){return;}var data = new DragDropData() { Tag = tag };//開啟準備拖動操作DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Copy);
}

?

注意,在調用DragDrop.DoDragDrop方法開始拖拽時,此方法有三個參數【DoDragDrop(DependencyObject dragSource, object data, DragDropEffects allowedEffects)】,說明如下:

  • 第一個參數是拖拽源控件。
  • 第二個參數用于傳遞數據,可以傳遞參數,用于區分詳細信息。
  • 第三個參數是拖拽效果

在畫布容器中松開拖拽的鼠標左鍵時,觸發畫布Drop事件,在此事件中創建新的控件,如下所示:

private ICommand canvasDropCommand;public ICommand CanvasDropCommand
{get {if (canvasDropCommand == null){canvasDropCommand = new RelayCommand<DragEventArgs>(CanvasDrop);}return canvasDropCommand; }
}private void CanvasDrop(DragEventArgs e)
{var data = e.Data.GetData(typeof(DragDropData)) as DragDropData;if (data != null){var position = e.GetPosition(this.containerCanvas);if (data.Tag == "Text"){//創建文本Border border = new Border();border.BorderThickness = new Thickness(1);border.BorderBrush = Brushes.Black;TextBlock text = new TextBlock(){Width = 120,Height = 30,Text = "文本1",FontSize = 14,Background = Brushes.LightGray,TextAlignment = TextAlignment.Center,Padding = new Thickness(5)};border.Child = text;border.MouseDown += Container_Control_MouseDown;border.MouseMove += Container_Control_MouseMove;border.MouseUp += Container_Control_MouseUp;this.containerCanvas.Children.Add(border);Canvas.SetLeft(border, position.X - 60);Canvas.SetTop(border, position.Y - 15);}if (data.Tag == "Button"){Button button = new Button(){Width = 120,Height = 30,Content = "按鈕1",FontSize = 14,Background = Brushes.LightGray,HorizontalContentAlignment = HorizontalAlignment.Center,VerticalContentAlignment = VerticalAlignment.Center,Padding = new Thickness(5),BorderBrush = Brushes.Black,BorderThickness = new Thickness(1)};button.AddHandler(Button.MouseDownEvent,new MouseButtonEventHandler( Container_Control_MouseDown),true);button.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(Container_Control_MouseMove), true);button.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(Container_Control_MouseUp), true);this.containerCanvas.Children.Add(button);Canvas.SetLeft(button, position.X - 60);Canvas.SetTop(button, position.Y - 15);}}
}

?

?注意:在此事件中,以下幾點需要注意:

  • 通過e.Data.GetData方法獲取傳遞的參數。
  • 通過e.GetPosition方法獲取鼠標相對位置。參數是相對的對象,如Canvas容器等。
  • 容器的Drop事件中,根據傳遞的內容創建控件對象,并為新創建的控件對象綁定MouseDown,MouseMove,MouseUp方法。其中Button按鈕,由于鼠標按下事件和本省自帶的Click事件相沖突,所以需要通過AddHandler方法添加鼠標事件。
  • 通過Canvas.SetLeft,Canvas.SetTop方法設置控件對象在畫布容器中的位置。

2. 控件拖動

在控件對象的MouseDown,MouseMove,MouseUp三個事件中,實現控件的拖動效果。即在MouseDown時開始,MouseMove中不斷設置控件的Left,Top的值隨鼠標而動,在MouseUp時停止

private void Container_Control_MouseUp(object sender, MouseButtonEventArgs e)
{if(e.LeftButton== MouseButtonState.Released){Mouse.Capture(null);}
}private void Container_Control_MouseMove(object sender, MouseEventArgs e)
{if (e.LeftButton == MouseButtonState.Pressed){var position = e.GetPosition(this.containerCanvas);Canvas.SetLeft((UIElement)sender,position.X-60);Canvas.SetTop((UIElement)sender,position.Y-15);}
}private void Container_Control_MouseDown(object sender, MouseButtonEventArgs e)
{if(e.LeftButton ==MouseButtonState.Pressed){Mouse.Capture((IInputElement)sender);}
}

?

注意,啟動Mouse.Capture功能是為了捕獲鼠標的焦點,使其在鼠標移動期間一直保持焦點,防止鼠標與控件分離

示例效果

本示例主要為了說明,只是簡單地 實現了控件拖拽,拖動等效果,具體如下所示:

以上就是WPF之控件拖拽與拖動的全部內容,希望能夠一起學習,共同進步。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/206641.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/206641.shtml
英文地址,請注明出處:http://en.pswp.cn/news/206641.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python---面向對象其他特性

1、類屬性 Python中&#xff0c;屬性可以分為實例屬性和類屬性。 類屬性就是 類對象中定義的屬性&#xff0c;它被該類的所有實例對象所共有。通常用來記錄 與這類相關 的特征&#xff0c;類屬性 不會用于記錄 具體對象的特征。 在Python中&#xff0c;一切皆對象。類也是一…

1 接口測試介紹

在軟件測試工作中&#xff0c;接口測試是必不可少的。接口測試一般是發生在單元測試之后&#xff0c;系統測試之前。當開發人員輸出API文檔后&#xff0c;測試人員就可以開始編寫接口測試用例了。接口測試可以讓測試人員更早的介入&#xff0c;不需要等待前后端聯調完成才開始測…

銀行卡二要素API的應用案例:從在線購物到金融投資

引言 隨著互聯網技術的不斷發展&#xff0c;人們的金融需求也在不斷增加。隨之而來的是各種新型金融服務的涌現&#xff0c;讓用戶的金融體驗更加便利快捷。其中&#xff0c;銀行卡二要素API的應用&#xff0c;則為用戶的金融體驗和安全性提供了極大的保障。 銀行卡二要素API…

知識蒸餾的蒸餾損失方法代碼總結(包括:基于logits的方法:KLDiv,dist,dkd等,基于中間層提示的方法:)

有兩種知識蒸餾方法&#xff1a;一種利用教師模型的輸出概率&#xff08;基于logits的方法&#xff09;[15,14,11]&#xff0c;另一種利用教師模型的中間表示&#xff08;基于提示的方法&#xff09;[12,13,18,17]。基于logits的方法利用教師的輸出作為輔助信號來訓練一個較小的…

VBA語法結構及編程思想

VBA&#xff08;Visual Basic for Applications&#xff09;是一種編程語言&#xff0c;它被用于Microsoft Office應用程序的自動化&#xff0c;允許用戶編寫宏來執行常規任務。VBA是基于Microsoft的Visual Basic語言&#xff0c;但專為Office應用程序定制。 VBA語法格式 VBA的…

【STM32】TIM定時器輸出比較

1 輸出比較 1.1 輸出比較簡介 OC&#xff08;Output Compare&#xff09;輸出比較&#xff1b;IC&#xff08;Input Capture&#xff09;輸入捕獲&#xff1b;CC&#xff08;Capture/Compare&#xff09;輸入捕獲和輸出比較的單元輸出比較可以通過比較CNT與CCR寄存器值&#…

JavaWeb-HTTP協議

1. 什么是HTTP協議 HTTP超文本傳輸協(Hyper Text transfer protocol)&#xff0c;是一種用于用于分布式、協作式和超媒體信息系統的應用層協議。它于1990年提出&#xff0c;經過十幾年的使用與發展&#xff0c;得到不斷地完善和擴展。HTTP 是為 Web 瀏覽器與 Web 服務器之間的…

AI自動生成代碼工具

AI自動生成代碼工具是一種利用人工智能技術來輔助或自動化軟件開發過程中的編碼任務的工具。這些工具使用機器學習和自然語言處理等技術&#xff0c;根據開發者的需求生成相應的源代碼。以下是一些常見的AI自動生成代碼工具&#xff0c;希望對大家有所幫助。北京木奇移動技術有…

Redisson的基本使用

Redisson官網描述&#xff1a;Redisson 是一個在 Redis 的基礎上實現的 Java 駐內存數據網格客戶端&#xff08;In-Memory Data Grid&#xff09;。它不僅提供了一系列的 redis 常用數據結構命令服務&#xff0c;還提供了許多分布式服務&#xff0c;例如分布式鎖、分布式對象、…

HCIP —— BGP 基礎 (上)

BGP --- 邊界網關協議 &#xff08;路徑矢量協議&#xff09; IGP --- 內部網關協議 --- OSPF RIP ISIS EGP --- 外部網關協議 --- EGP BGP AS --- 自治系統 由單一的組織或者機構獨立維護的網絡設備以及網絡資源的集合。 因 網絡范圍太大 需 自治 。 為區分不同的AS&#…

vim常見操作

vim常見操作 文章目錄 vim常見操作1. 回退/前進2. 搜索3. 刪除4. 定位到50行5. 顯示行號6. 復制粘貼7. 剪貼8. 替換9. vim打開文件的時候出現 1. 回退/前進 1.esc進入命令模式 2.ctrlr 前進 u 回退2. 搜索 1&#xff09; esc進入命令模式 2&#xff09; /text  查找text&am…

Docker load 命令

docker load &#xff1a;導入使用docker save命令導出的鏡像。 語法 docker load [OPTIONS]OPTIONS 說明&#xff1a; --input , -i &#xff1a;指定導入的文件&#xff0c;代替STDIN。 --quiet , -q &#xff1a;精簡輸出信息。 實例&#xff1a; 導入鏡像&#xff1a…

【STM32】TIM定時器輸入捕獲

1 輸入捕獲 1.1 輸入捕獲簡介 IC&#xff08;Input Capture&#xff09;輸入捕獲 輸入捕獲模式下&#xff0c;當通道輸入引腳出現指定電平跳變時&#xff08;上升沿/下降沿&#xff09;&#xff0c;當前CNT的值將被鎖存到CCR中&#xff08;把CNT的值讀出來&#xff0c;寫入到…

ubuntu16.04安裝ROS+Gazebo

ubuntu16.04安裝ROS參考文章 ros安裝&#xff08;一鍵最簡安裝&#xff0c;吹爆魚香ROS&#xff0c;請叫我魚吹&#xff09; ROS篇——Ubuntu快速一鍵安裝ROS或ROS2&#xff08;通用&#xff09; ubuntu安裝ROS melodic(最新、超詳細圖文教程) 配置ubuntu以及安裝ros2必要環…

類風濕性關節炎口腔黏膜破裂引發抗瓜氨酸細菌和人蛋白抗體反應

今天給同學們分享一篇實驗文章“Oral mucosal breaks trigger anti-citrullinated bacterial and human protein antibody responses in rheumatoid arthritis”&#xff0c;這篇文章發表在Sci Transl Med期刊上&#xff0c;影響因子為17.1。 結果解讀&#xff1a; 口腔黏膜破…

Redis主從復制的配置和實現原理

Redis的持久化功能在一定程度上保證了數據的安全性&#xff0c;即便是服務器宕機的情況下&#xff0c;也可以保證數據的丟失非常少。通常&#xff0c;為了避免服務的單點故障&#xff0c;會把數據復制到多個副本放在不同的服務器上&#xff0c;且這些擁有數據副本的服務器可以用…

如何快速構建知識服務平臺,打造個人或企業私域流量

隨著互聯網的快速發展&#xff0c;傳統的知識付費平臺已經不能滿足用戶的需求。而SaaS知識付費小程序平臺則是一種新型的知識付費方式&#xff0c;具有靈活、便捷、高效等特點&#xff0c;為用戶提供了更加優質的付費知識服務。本文將介紹如何搭建自己的SaaS知識付費小程序平臺…

如何掌握構建 LMS 網站的藝術

目錄 什么是學習管理系統 (LMS) 在線課程和 LMS 網站的好處 為什么 WordPress 對于 LMS 網站很重要 統一學習中心 多功能性和可擴展性 提高教育參與度 簡化管理和監控 節省時間和費用 技能評估和績效監督 持續學習和技能提升 使用 WordPress 插件構建成功的 LMS 課程 專注于您的…

sparkc程序idea調試提示內存不足

報錯如下&#xff1a; Exception in thread "main" java.lang.IllegalArgumentException: System memory 259522560 must be at least 471859200. Please increase heap size using the --driver-memory option or spark.driver.memory in Spark configuration. 測…

自動駕駛:傳感器初始標定

手眼標定 機器人手眼標定AxxB&#xff08;eye to hand和eye in hand&#xff09;及平面九點法標定 Ax xB問題求解&#xff0c;旋轉和平移分步求解法 手眼標定AXXB求解方法&#xff08;文獻總結&#xff09; 基于靶的方法 相機標定 (1) ApriTag (2) 棋盤格&#xff1a;cv::f…