翼度科技»论坛 编程开发 .net 查看内容

浅谈WPF之控件拖拽与拖动

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。

 
涉及知识点

 
WPF控件的拖拽与拖动,主要涉及知识点如下所示:

  • 容器布局,本示例采用左右布局,主容器采用Grid并分成两列进行布局,左侧图标库采用UniformGrid布局,右侧画布采用Canvas布局。
  • 控件拖拽,当图标库中的图标控件被鼠标按下时,通过调用 DragDrop.DoDragDrop方法实现拖拽功能,并且设置画布的AllowDrop属性为true,并触发拖拽松开事件
  • 控件拖动,当图标库中的图标拖拽到新画布容器后,就会生成一个新的控件,通过属性按下事件,鼠标移动事件,鼠标升起事件,来实现控件的拖动
 
实现步骤

 
1. 页面布局

 
根据布局说明,页面分为左右两部分【Grid容器】,左侧图标库【UniformGrid】,右侧画布【Canvas】,如下所示:
  1. <Window x:
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
  5.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  7.         xmlns:local="clr-namespace:DemoDragAndDrop"
  8.         mc:Ignorable="d"
  9.         Title="MainWindow" Height="450" Width="800">
  10.     <i:Interaction.Triggers>
  11.         <i:EventTrigger EventName="Loaded">
  12.             <i:InvokeCommandAction Command="{Binding WinLoadedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
  13.         </i:EventTrigger>
  14.     </i:Interaction.Triggers>
  15.     <Grid>
  16.         <Grid.ColumnDefinitions>
  17.             <ColumnDefinition Width="Auto"></ColumnDefinition>
  18.             <ColumnDefinition Width="*"></ColumnDefinition>
  19.         </Grid.ColumnDefinitions>
  20.         <Border Grid.Column="0" BorderBrush="LightGray" BorderThickness="1"></Border>
  21.         <Border Grid.Column="1" BorderBrush="LightGray" BorderThickness="1"></Border>
  22.         <UniformGrid Grid.Column="0" Columns="2" VerticalAlignment="Top">
  23.             <UniformGrid.Resources>
  24.                
  25.             </UniformGrid.Resources>
  26.             <TextBlock Text="文本" Tag="Text">
  27.                 <i:Interaction.Triggers>
  28.                     <i:EventTrigger EventName="MouseLeftButtonDown">
  29.                         <i:InvokeCommandAction Command="{Binding IconMouseLeftDownCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBlock}}"/>
  30.                     </i:EventTrigger>
  31.                 </i:Interaction.Triggers>
  32.             </TextBlock>
  33.             <TextBlock Text="按钮" Tag="Button">
  34.                 <i:Interaction.Triggers>
  35.                     <i:EventTrigger EventName="MouseLeftButtonDown">
  36.                         <i:InvokeCommandAction Command="{Binding IconMouseLeftDownCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBlock}}"/>
  37.                     </i:EventTrigger>
  38.                 </i:Interaction.Triggers>
  39.             </TextBlock>
  40.             <TextBlock Text="单选按钮"></TextBlock>
  41.             <TextBlock Text="复选按钮"></TextBlock>
  42.             <TextBlock Text="圆形"></TextBlock>
  43.             <TextBlock Text="长方形"></TextBlock>
  44.             <TextBlock Text="直线"></TextBlock>
  45.             <TextBlock Text="三角形"></TextBlock>
  46.         </UniformGrid>
  47.         <Canvas x:Name="container" Grid.Column="1" AllowDrop="True" Background="White">
  48.             <i:Interaction.Triggers>
  49.                 <i:EventTrigger EventName="Drop">
  50.                     <i:InvokeCommandAction Command="{Binding CanvasDropCommand}" PassEventArgsToCommand="True"/>
  51.                 </i:EventTrigger>
  52.             </i:Interaction.Triggers>
  53.         </Canvas>
  54.     </Grid>
  55. </Window>
复制代码
注意,在页面布局中,为图标库中的图标绑定了MouseLeftButtonDown事件命令,当鼠标左键按下时触发对应的事件,并开始拖拽。如下所示:
  1. private ICommand  iconMouseLeftDownCommand;
  2. public ICommand IconMouseLeftDownCommand
  3. {
  4.         get {
  5.                 if (iconMouseLeftDownCommand == null)
  6.                 {
  7.                         iconMouseLeftDownCommand = new RelayCommand<object>(IconMouseLeftDown);
  8.                 }
  9.                 return iconMouseLeftDownCommand;
  10.         }
  11. }
  12. private void IconMouseLeftDown(object sender)
  13. {
  14.         var tag = (sender as TextBlock)?.Tag?.ToString();
  15.         if (tag == null)
  16.         {
  17.                 return;
  18.         }
  19.         var data = new DragDropData() { Tag = tag };
  20.         //开启准备拖动操作
  21.         DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Copy);
  22. }
复制代码
注意,在调用DragDrop.DoDragDrop方法开始拖拽时,此方法有三个参数【DoDragDrop(DependencyObject dragSource, object data, DragDropEffects allowedEffects)】,说明如下:

  • 第一个参数是拖拽源控件。
  • 第二个参数用于传递数据,可以传递参数,用于区分详细信息。
  • 第三个参数是拖拽效果
在画布容器中松开拖拽的鼠标左键时,触发画布Drop事件,在此事件中创建新的控件,如下所示:
  1. private ICommand canvasDropCommand;
  2. public ICommand CanvasDropCommand
  3. {
  4.         get {
  5.                 if (canvasDropCommand == null)
  6.                 {
  7.                         canvasDropCommand = new RelayCommand<DragEventArgs>(CanvasDrop);
  8.                 }
  9.                 return canvasDropCommand;
  10.         }
  11. }
  12. private void CanvasDrop(DragEventArgs e)
  13. {
  14.         var data = e.Data.GetData(typeof(DragDropData)) as DragDropData;
  15.         if (data != null)
  16.         {
  17.                 var position = e.GetPosition(this.containerCanvas);
  18.                 if (data.Tag == "Text")
  19.                 {
  20.                         //创建文本
  21.                         Border border = new Border();
  22.                         border.BorderThickness = new Thickness(1);
  23.                         border.BorderBrush = Brushes.Black;
  24.                         TextBlock text = new TextBlock()
  25.                         {
  26.                                 Width = 120,
  27.                                 Height = 30,
  28.                                 Text = "文本1",
  29.                                 FontSize = 14,
  30.                                 Background = Brushes.LightGray,
  31.                                 TextAlignment = TextAlignment.Center,
  32.                                 Padding = new Thickness(5)
  33.                         };
  34.                         border.Child = text;
  35.                         border.MouseDown += Container_Control_MouseDown;
  36.                         border.MouseMove += Container_Control_MouseMove;
  37.                         border.MouseUp += Container_Control_MouseUp;
  38.                         this.containerCanvas.Children.Add(border);
  39.                         Canvas.SetLeft(border, position.X - 60);
  40.                         Canvas.SetTop(border, position.Y - 15);
  41.                 }
  42.                 if (data.Tag == "Button")
  43.                 {
  44.                         Button button = new Button()
  45.                         {
  46.                                 Width = 120,
  47.                                 Height = 30,
  48.                                 Content = "按钮1",
  49.                                 FontSize = 14,
  50.                                 Background = Brushes.LightGray,
  51.                                 HorizontalContentAlignment = HorizontalAlignment.Center,
  52.                                 VerticalContentAlignment = VerticalAlignment.Center,
  53.                                 Padding = new Thickness(5),
  54.                                 BorderBrush = Brushes.Black,
  55.                                 BorderThickness = new Thickness(1)
  56.                         };
  57.                         button.AddHandler(Button.MouseDownEvent,new MouseButtonEventHandler( Container_Control_MouseDown),true);
  58.                         button.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(Container_Control_MouseMove), true);
  59.                         button.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(Container_Control_MouseUp), true);
  60.                         this.containerCanvas.Children.Add(button);
  61.                         Canvas.SetLeft(button, position.X - 60);
  62.                         Canvas.SetTop(button, position.Y - 15);
  63.                 }
  64.         }
  65. }
复制代码
 注意:在此事件中,以下几点需要注意:

  • 通过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时停止
  1. private void Container_Control_MouseUp(object sender, MouseButtonEventArgs e)
  2. {
  3.         if(e.LeftButton== MouseButtonState.Released)
  4.         {
  5.                 Mouse.Capture(null);
  6.         }
  7. }
  8. private void Container_Control_MouseMove(object sender, MouseEventArgs e)
  9. {
  10.         if (e.LeftButton == MouseButtonState.Pressed)
  11.         {
  12.                 var position = e.GetPosition(this.containerCanvas);
  13.                 Canvas.SetLeft((UIElement)sender,position.X-60);
  14.                 Canvas.SetTop((UIElement)sender,position.Y-15);
  15.         }
  16. }
  17. private void Container_Control_MouseDown(object sender, MouseButtonEventArgs e)
  18. {
  19.         if(e.LeftButton ==MouseButtonState.Pressed)
  20.         {
  21.                 Mouse.Capture((IInputElement)sender);
  22.         }
  23. }
复制代码
注意,启动Mouse.Capture功能是为了捕获鼠标的焦点,使其在鼠标移动期间一直保持焦点,防止鼠标与控件分离
 
示例效果

 
本示例主要为了说明,只是简单地 实现了控件拖拽,拖动等效果,具体如下所示:

以上就是WPF之控件拖拽与拖动的全部内容,希望能够一起学习,共同进步。

来源:https://www.cnblogs.com/hsiang/archive/2023/12/08/17884276.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具