知識點:
- 創建自定義用戶控件(UserControl)
- 使用戶控件成為拖動源
- 使用戶控件成為放置目標
- 使面板能夠接收從用戶控件放置的數據
創建項目:
1、新建WPF項目(Wpf-AllowDrop)
2、在MainWindow.xaml的 Grid控件添加源碼
<Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0" Background="Beige"> <TextBox Width="Auto" Margin="2" Text="green"/> </StackPanel> <StackPanel Grid.Column="1" Background="Bisque"> </StackPanel>
設計顯示效果如下:
項目中添加用戶控件
1、“項目”--> “添加用戶控件”
2、重命名為Circle.xaml,添加。
3、在Circle.xaml的Grid中添加 Ellipse標簽
<Ellipse x:Name="circleUI" Height="100" Width="100" Fill="Blue" />
顯示效果如下:
4、在Circle.xaml.cs源文件中,重寫構造函數
public partial class Circle : UserControl { public Circle() { InitializeComponent(); } public Circle(Circle c) //重寫構造 { InitializeComponent(); this.circleUI.Height = c.circleUI.Height; this.circleUI.Width = c.circleUI.Height; this.circleUI.Fill = c.circleUI.Fill; } }
5、在MainWindow.xaml中的第一個StackPanel中添加兩個自定義的圓控件
<StackPanel Grid.Column="0" Background="Beige"> <TextBox Width="Auto" Margin="2" Text="green"/> <!--添加圓控件--> <local:Circle Margin="2" /> <local:Circle Margin="2" /> </StackPanel>
效果圖如下:
用戶控件實現拖動源事件
1、在Circle.xaml.cs中重寫OnMouseMove事件
protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // 判斷左鍵是否按下 if (e.LeftButton == MouseButtonState.Pressed) { //聲明DataObject,並打包圓控件的圖像繪制方式(包含顏色)、高度及其副本。 DataObject data = new DataObject(); data.SetData(DataFormats.StringFormat, circleUI.Fill.ToString()); data.SetData("Double", circleUI.Height); data.SetData("Object", this); //使用DragDrop的DoDragDrop方法開啟拖動功能。拖動方式為拖動復制或移動 DragDrop.DoDragDrop(this, data, DragDropEffects.Copy | DragDropEffects.Move); } }
2、運行測試:單擊一個圓,任意拖動查看效果:
3、重寫OnGiveFeedback,增強拖動時,光標反饋效果。
protected override void OnGiveFeedback(GiveFeedbackEventArgs e) { base.OnGiveFeedback(e); //Effects獲取拖動類型 if (e.Effects.HasFlag(DragDropEffects.Copy)) { Mouse.SetCursor(Cursors.Cross); //拖動復制顯示紅十字 } else if (e.Effects.HasFlag(DragDropEffects.Move)) { Mouse.SetCursor(Cursors.Pen); //移動顯示筆形 } else { Mouse.SetCursor(Cursors.No); } e.Handled = true; }
4、運行測試:單擊一個圓,任意拖動查看效果(主要指針效果)。
用戶控件成為放置目標
1、在Circle.xaml的UserControl標記中添加AllowDrop屬性為"True"
<UserControl x:Class="Wpf_AllowDrop.Circle" 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:Wpf_AllowDrop" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" AllowDrop="True">
2、在Circle.xaml.cs源碼文件中,重寫OnDrop事件方法
protected override void OnDrop(DragEventArgs e) { base.OnDrop(e); //檢查數據是否包含制定字符串類型數據 if (e.Data.GetDataPresent(DataFormats.StringFormat)) { //獲取字符串 string dataString = (string)e.Data.GetData(DataFormats.StringFormat); //使用BrushConverter將字符串轉換成Brush對象並應用於提供圓形控件 UI 的 Ellipse 的 Fill BrushConverter converter = new BrushConverter(); if (converter.IsValid(dataString)) { Brush newFill = (Brush)converter.ConvertFromString(dataString); circleUI.Fill = newFill; if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey)) { e.Effects = DragDropEffects.Copy; } else { e.Effects = DragDropEffects.Move; } } } e.Handled = true; }
3、運行測試,查看TextBox文本green拖入圓形區域后效果:
4、重寫OnDragOver,禁止無效顏色拖入圓形控件(鼠標顯示禁止)
protected override void OnDragOver(DragEventArgs e) { base.OnDragOver(e); //設置Effects 為不接受數據 e.Effects = DragDropEffects.None; if (e.Data.GetDataPresent(DataFormats.StringFormat)) { string dataString = (string)e.Data.GetData(DataFormats.StringFormat); BrushConverter converter = new BrushConverter(); //判斷拖動值是否有效 if (converter.IsValid(dataString)) { //判斷Ctrl鍵是否按下 if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey)) { e.Effects = DragDropEffects.Copy; } else { e.Effects = DragDropEffects.Move; } } } e.Handled = true; }
5、運行測試,拖動Gre到圓型中,查看鼠標變化
6、添加一個Brush變量用來暫時存放目標控件屬性,重寫OnDrageEnter和OneDrageLeave,增加預覽效果,未放置則離開,目標控件顏色不發生變化。
public partial class Circle : UserControl { private Brush _previousFill = null; //聲明私有Brush,初始值為null
protected override void OnDragEnter(DragEventArgs e) { base.OnDragEnter(e); //控件原始屬性存放在全局私有Brush對象中 _previousFill = circleUI.Fill; if (e.Data.GetDataPresent(DataFormats.StringFormat)) { string dataString = (string)e.Data.GetData(DataFormats.StringFormat); BrushConverter converter = new BrushConverter(); if (converter.IsValid(dataString)) { Brush newFill = (Brush)converter.ConvertFromString(dataString.ToString()); circleUI.Fill = newFill; } } }
protected override void OnDragLeave(DragEventArgs e) { base.OnDragLeave(e); //若直接離開(未釋放鼠標),把存在全局私有變量_previousFill屬性重新賦值 circleUI.Fill = _previousFill; }
7、運行測試,拖動時先不釋放鼠標測試,再是否鼠標測試,查看效果:
使面板能夠接受放置的數據
1、在MainWindow.xaml 的兩個StackPanel控件中添加DragOver事件處理,名稱為panel_DragOver,以及添加Drop事件處理,名稱為panel_drop。並設置AllowDrop屬性為"True"。
<StackPanel Grid.Column="0" Background="Beige" AllowDrop="True" DragOver="panel_DragOver" Drop="panel_Drop"> <TextBox Width="Auto" Margin="2" Text="green"/> <!--添加圓控件--> <local:Circle Margin="2" /> <local:Circle Margin="2" /> </StackPanel> <StackPanel Grid.Column="1" Background="Bisque" AllowDrop="True" DragOver="panel_DragOver" Drop="panel_Drop"> </StackPanel>
2、在MainWindow.xaml.cs中實現兩個事件處理方法:
private void panel_DragOver(object sender, DragEventArgs e) { //檢查拖動的數據是否包含由圓形用戶控件打包在 DataObject 中並且在 DoDragDrop 調用中傳遞的“對象”數據 if (e.Data.GetDataPresent("Object")) { if (e.KeyStates == DragDropKeyStates.ControlKey) { e.Effects = DragDropEffects.Copy; } else { e.Effects = DragDropEffects.Move; } } }
private void panel_Drop(object sender, DragEventArgs e) { if (e.Handled == false) { Panel _panel = (Panel)sender; //取得當前panel對象 UIElement _element = (UIElement)e.Data.GetData("Object");//移動對象轉換成WPF核心基類對象 if (_panel != null && _element != null) { //獲取移動對象的父對象 Panel _parent = (Panel)VisualTreeHelper.GetParent(_element); if (_parent != null) { if (e.KeyStates == DragDropKeyStates.ControlKey && e.AllowedEffects.HasFlag(DragDropEffects.Copy)) { Circle _circle = new Circle((Circle)_element); _panel.Children.Add(_circle); //在其子元素中添加對象 e.Effects = DragDropEffects.Copy; } else if (e.AllowedEffects.HasFlag(DragDropEffects.Move)) { _parent.Children.Remove(_element); //移動時,從父對象中移除源文件 _panel.Children.Add(_element); e.Effects = DragDropEffects.Move; } } } } }
3、運行測試,隨意拖動查看效果: