本程序 是用WPF开发的一个DEMO,您可以用鼠标左键拖拽 其中一个格子中的控件 与 另外的格子中控件交换位置。这是一个很基础的例子在工作中,可以发挥更多的想像让它更加丰富。
用Grid控件在前台做一个3X3的九宫格窗体。
<Window x:Class="WpfApp拖拽换位.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp拖拽换位"
mc:Ignorable="d"
Title="拖拽换位" Height="450" Width="800" WindowStartupLocation="CenterScreen">
<Grid Name="myGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
Grid.RowDefinitions>
Grid>
Window>
在程序打开时向Grid的格子中加入TextBlock控件 并生成随机的背景色。
public MainWindow()
{
InitializeComponent();
InitControls();
}
///
/// 向Grid的格子中加TextBlock控件
///
void InitControls()
{
int k = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
SolidColorBrush scb = new SolidColorBrush(GetRandomColor());
TextBlock tb = new TextBlock();
tb.Background = scb;
tb.Text = "控件" + k;
tb.SetValue(Grid.RowProperty, i);
tb.SetValue(Grid.ColumnProperty, j);
tb.FontSize = 20;
tb.Foreground = new SolidColorBrush(Color.FromRgb(255,255,255));
//tb.VerticalAlignment = VerticalAlignment.Center;
//tb.HorizontalAlignment= HorizontalAlignment.Center;
myGrid.Children.Add(tb);
k++;
}
}
myGrid.MouseLeftButtonDown += Element_MouseLeftButtonDown;
myGrid.MouseLeftButtonUp += Element_MouseLeftButtonUp;
myGrid.PreviewMouseMove += Element_PreviewMouseMove;
}
Random random = new Random();
public Color GetRandomColor()
{
return Color.FromRgb((byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255));
}
利用这个Popup控件做为被点中的控件载体,并可以跟随鼠标移动
private void CreatePopup(Visual dragElement, MouseButtonEventArgs e)
{
//使用PointToScreen函数可以将点转换为屏幕坐标
//首先获取当前窗体的左上角和右下角两点的坐标
Point ptLeftUp = new Point(0, 0);
//转换获取到这个窗口相对于屏幕两个坐标
ptLeftUp = this.PointToScreen(ptLeftUp);
//获取myGrid的实际宽高
double y = e.GetPosition(this.myGrid).Y;
double x = e.GetPosition(myGrid).X;
this._MyPopup = new Popup();
Border border = new Border();
border.Margin= new Thickness(0,0,8,8);
DropShadowEffect effect = new DropShadowEffect();
effect.Opacity = 1;
effect.ShadowDepth = -14;
effect.BlurRadius = 9;
effect.Color = Color.FromArgb(100, 0, 0, 0);
border.Effect = effect;
Rectangle r = new Rectangle();
r.Width = ((FrameworkElement)dragElement).ActualWidth;
r.Height = ((FrameworkElement)dragElement).ActualHeight;
r.Fill = new VisualBrush(dragElement);
border.Child = r;
this._MyPopup.Child = border;
_MyPopup.AllowsTransparency = true;
_MyPopup.HorizontalOffset = ptLeftUp.X + x - ((FrameworkElement)ultUE).ActualWidth / 2;
_MyPopup.VerticalOffset = ptLeftUp.Y + y - ((FrameworkElement)ultUE).ActualHeight / 2;
this._MyPopup.IsOpen = true;
}
利用Opacity 属性来控制拖动时每个格子的动画效果。
void SetOpacity(double Opacity)
{
foreach (UIElement element in myGrid.Children)
{
if (element != ultUE)
{
element.Opacity = Opacity;
}
}
}
通过grid的行例来查到格子中的控件。
private UIElement GetChildren(Grid grid, int row, int column)
{
foreach (UIElement child in grid.Children)
{
if (Grid.GetRow(child) == row && Grid.GetColumn(child) == column)
{
return child;
}
}
return null;
}
当鼠标左键按下时,获取点中的grid的一个格子并获取当中的控件,将这个控件的图像创建到Popup控件上显示出来。
private void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//isDown变量是防止多次操作。
if (isDown)
{
isDown = false;
return;
}
ultUE = (UIElement)e.Source;
ultUE.CaptureMouse();//设置了鼠标捕获,这样它可以不受到其它控件的影响。
initPt = new Point(e.GetPosition(ultUE).X, e.GetPosition(ultUE).Y);
SetOpacity(moveOpacity);
CreatePopup(ultUE, e);
isDown = true;
}
当鼠标按住左键并拖动时,设置Popup控件的位置与获取鼠标的位置相同。
private void Element_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (isDown == false) return;
Point ptLeftUp = new Point(0, 0);
Point ptRightDown = new Point(this.ActualWidth, this.ActualHeight);
ptLeftUp = this.PointToScreen(ptLeftUp);
ptRightDown = this.PointToScreen(ptRightDown);
double y = e.GetPosition(myGrid).Y;
double x = e.GetPosition(myGrid).X;
if (_MyPopup != null)
{
//下面两句是设置Popup控件的位置除以2是想让鼠标在它的中心
_MyPopup.HorizontalOffset = ptLeftUp.X+ x-((FrameworkElement)ultUE).ActualWidth / 2;
_MyPopup.VerticalOffset = ptLeftUp.Y+ y - ((FrameworkElement)ultUE).ActualHeight / 2;
}
double start = 0.0;
int row = 0;
foreach (RowDefinition rd in myGrid.RowDefinitions)
{
start += rd.ActualHeight;
if (y < start)
{
break;
}
row++;
}
double cstart = 0.0;
int column = 0;
foreach (ColumnDefinition cd in myGrid.ColumnDefinitions)
{
cstart += cd.ActualWidth;
if (x < cstart)
{
break;
}
column++;
}
//下面的代码是当鼠标移动到哪个格子哪个格子就会亮起来。
UIElement uIElement = GetChildren(myGrid, row, column);
foreach (UIElement element in myGrid.Children)
{
if (element != ultUE && element != uIElement)
{
element.Opacity = moveOpacity;
}
else
{
element.Opacity = 1;
}
}
}
当鼠标按住左键放开时,设置Popup控件关闭,同时交换选中的两个控件的位置。
private void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!isDown) return;
isDown = false;
if (this._MyPopup != null)
{
this._MyPopup.IsOpen = false;
this._MyPopup.Child = null;
this._MyPopup = null;
}
SetOpacity(1);
ultUE.ReleaseMouseCapture();//当控件具有鼠标捕获的话,则释放该捕获。
double y = e.GetPosition(myGrid).Y;//获取鼠标抬起时的控件的位置 Y值
double start = 0.0;
int row = 0;
foreach (RowDefinition rd in myGrid.RowDefinitions)
{
start += rd.ActualHeight;
if (y < start)
{
break;
}
row++;
}
double x = e.GetPosition(myGrid).X;//获取鼠标抬起时的控件的位置 X值
double cstart = 0.0;
int column = 0;
foreach (ColumnDefinition cd in myGrid.ColumnDefinitions)
{
cstart += cd.ActualWidth;
if (x < cstart)
{
break;
}
column++;
}
var initRow = Grid.GetRow(ultUE);//找到控件所在的行
var initCol = Grid.GetColumn(ultUE);//找到控件所在的列
UIElement uIElement = null;
if (row != initRow || column != initCol)
{
uIElement = GetChildren(myGrid, row, column);
}
if (uIElement != null)
{
//下面是交换两个控件的位置 (需要先移除再加载)
myGrid.Children.Remove(uIElement);
Grid.SetColumn(ultUE, column);//指定控件在grid中哪行哪例
Grid.SetRow(ultUE, row);
myGrid.Children.Add(uIElement);
Grid.SetColumn(uIElement, initCol);
Grid.SetRow(uIElement, initRow);
}
}
--------------------------------------------------------------------------------------------------------------------
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shapes;
namespace WpfApp拖拽换位
{
public partial class MainWindow : Window
{
private UIElement ultUE;
private Point initPt;
private Popup _MyPopup = null;
private bool isDown = false;
private double moveOpacity = 0.3;
Random random = new Random();
#region 初始化
public MainWindow()
{
InitializeComponent();
InitControls();
}
void InitControls()
{
int k = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
SolidColorBrush scb = new SolidColorBrush(GetRandomColor());
TextBlock tb = new TextBlock();
tb.Background = scb;
tb.Text = "控件" + k;
tb.SetValue(Grid.RowProperty, i);
tb.SetValue(Grid.ColumnProperty, j);
tb.FontSize = 20;
tb.Foreground = new SolidColorBrush(Color.FromRgb(255,255,255));
myGrid.Children.Add(tb);
k++;
}
}
myGrid.MouseLeftButtonDown += Element_MouseLeftButtonDown;
myGrid.MouseLeftButtonUp += Element_MouseLeftButtonUp;
myGrid.PreviewMouseMove += Element_PreviewMouseMove;
}
public Color GetRandomColor()
{
return Color.FromRgb((byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255));
}
#endregion
#region 鼠标操作拖放功能
void SetOpacity(double Opacity)
{
foreach (UIElement element in myGrid.Children)
{
if (element != ultUE)
{
element.Opacity = Opacity;
}
}
}
private void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (isDown)
{
isDown = false;
return;
}
ultUE = (UIElement)e.Source;
ultUE.CaptureMouse();
initPt = new Point(e.GetPosition(ultUE).X, e.GetPosition(ultUE).Y);
SetOpacity(moveOpacity);
CreatePopup(ultUE, e);
isDown = true;
}
private void Element_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (isDown == false) return;
Point ptLeftUp = new Point(0, 0);
Point ptRightDown = new Point(this.ActualWidth, this.ActualHeight);
ptLeftUp = this.PointToScreen(ptLeftUp);
ptRightDown = this.PointToScreen(ptRightDown);
double y = e.GetPosition(myGrid).Y;
double x = e.GetPosition(myGrid).X;
if (_MyPopup != null)
{
_MyPopup.HorizontalOffset = ptLeftUp.X+ x-((FrameworkElement)ultUE).ActualWidth / 2;
_MyPopup.VerticalOffset = ptLeftUp.Y+ y - ((FrameworkElement)ultUE).ActualHeight / 2;
}
double start = 0.0;
int row = 0;
foreach (RowDefinition rd in myGrid.RowDefinitions)
{
start += rd.ActualHeight;
if (y < start)
{
break;
}
row++;
}
double cstart = 0.0;
int column = 0;
foreach (ColumnDefinition cd in myGrid.ColumnDefinitions)
{
cstart += cd.ActualWidth;
if (x < cstart)
{
break;
}
column++;
}
UIElement uIElement = GetChildren(myGrid, row, column);
foreach (UIElement element in myGrid.Children)
{
if (element != ultUE && element != uIElement)
{
element.Opacity = moveOpacity;
}
else
{
element.Opacity = 1;
}
}
}
private void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!isDown) return;
isDown = false;
if (this._MyPopup != null)
{
this._MyPopup.IsOpen = false;
this._MyPopup.Child = null;
this._MyPopup = null;
}
SetOpacity(1);
ultUE.ReleaseMouseCapture();
double y = e.GetPosition(myGrid).Y;
double start = 0.0;
int row = 0;
foreach (RowDefinition rd in myGrid.RowDefinitions)
{
start += rd.ActualHeight;
if (y < start)
{
break;
}
row++;
}
double x = e.GetPosition(myGrid).X;
double cstart = 0.0;
int column = 0;
foreach (ColumnDefinition cd in myGrid.ColumnDefinitions)
{
cstart += cd.ActualWidth;
if (x < cstart)
{
break;
}
column++;
}
var initRow = Grid.GetRow(ultUE);
var initCol = Grid.GetColumn(ultUE);
UIElement uIElement = null;
if (row != initRow || column != initCol)
{
uIElement = GetChildren(myGrid, row, column);
}
if (uIElement != null)
{
myGrid.Children.Remove(uIElement);
Grid.SetColumn(ultUE, column);
Grid.SetRow(ultUE, row);
myGrid.Children.Add(uIElement);
Grid.SetColumn(uIElement, initCol);
Grid.SetRow(uIElement, initRow);
}
}
private UIElement GetChildren(Grid grid, int row, int column)
{
foreach (UIElement child in grid.Children)
{
if (Grid.GetRow(child) == row && Grid.GetColumn(child) == column)
{
return child;
}
}
return null;
}
private void CreatePopup(Visual dragElement, MouseButtonEventArgs e)
{
Point ptLeftUp = new Point(0, 0);
ptLeftUp = this.PointToScreen(ptLeftUp);
double y = e.GetPosition(this.myGrid).Y;
double x = e.GetPosition(myGrid).X;
this._MyPopup = new Popup();
Border border = new Border();
border.Margin= new Thickness(0,0,8,8);
DropShadowEffect effect = new DropShadowEffect();
effect.Opacity = 1;
effect.ShadowDepth = -14;
effect.BlurRadius = 9;
effect.Color = Color.FromArgb(100, 0, 0, 0);
border.Effect = effect;
Rectangle r = new Rectangle();
r.Width = ((FrameworkElement)dragElement).ActualWidth;
r.Height = ((FrameworkElement)dragElement).ActualHeight;
r.Fill = new VisualBrush(dragElement);
border.Child = r;
this._MyPopup.Child = border;
_MyPopup.AllowsTransparency = true;
_MyPopup.HorizontalOffset = ptLeftUp.X + x - ((FrameworkElement)ultUE).ActualWidth / 2;
_MyPopup.VerticalOffset = ptLeftUp.Y + y - ((FrameworkElement)ultUE).ActualHeight / 2;
this._MyPopup.IsOpen = true;
}
#endregion
}
}
--------------------------------------------------------------------------------------------------------------------
工作好多年了,第一次在CSDN上发文章,希望能够对大家有帮助。
后面如果有时间的话我会把这个功能在项目里结合其它功能的实例也总结发布出来。
谢谢大家。
链接: .net6 WPF 开发的可拖拽 换位 九宫格