C# 移动自己的控件并使它们可放置
本文关键字:移动 自己的 控件 | 更新日期: 2023-09-27 17:56:25
早上好!昨天,我在尝试在WinForms
应用程序中为自己的控件实现自定义 DragDrop 时遇到了问题。
我有一个窗体,可以动态创建我自己的两个控件的实例。这些控件由一些控件本身组成,例如按钮、标签和列表框/树视图。控件用作特定数据集的表示形式。现在,我们都知道VS中的类图。那里有这些代表类的框。您可以通过执行(我称之为)来移动画布上的框,就像拖动文件一样。为了使用我自己的控件实现此目的,我做了以下操作:
public partial class MyControl: UserControl
{
private Control activeControl;
private void GeneralMouseDown(MouseEventArgs e)
{
activeControl = this;
previousLocation = e.Location;
Cursor = Cursors.Hand;
}
private void GeneralMouseMove(Control sender, MouseEventArgs e)
{
if (activeControl == null || activeControl != sender)
return;
var location = activeControl.Location;
location.Offset(e.Location.X - previousLocation.X, e.Location.Y - previousLocation.Y);
activeControl.Location = location;
}
private void GeneralMouseUp()
{
activeControl = null;
Cursor = Cursors.Default;
}
}
我想"抓取"用于拖动的控件MyControl
其 MouseDown-、MouseMove- 和 MouseUp-事件指向这三个方法。因此,我可以随心所欲地在窗体上自由移动我的控件。
棘手的一点来了:我有控件的数据集可以位于分层依赖项中,这意味着一个控件表示另一个控件的组件的详细信息,这就是我的控件具有列表框或树视图的原因。为了建立这样的分层依赖关系,我非常想将低阶控件拖放到我的高阶控件的列表框中,从而导致数据传输。
我知道如何为列表框设置DragEnter
和DragDrop
方法,就像我以前对文件所做的那样。只是为了完整起见:
private void lst_MyControl_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
问题是:当我移动我的控件时(在每个位置都会重新绘制,产生非常想要的效果!),当我将其"拖动"到目标列表框上时,DragEnter
事件不会被触发。我想我可以通过告诉Windows"嘿,我,在这里拖放!"来解决这个问题,从而添加到我的GeneralMouseDown
方法中:
this.DoDragDrop(this, DragDropEffects.Move);
一方面,这会触发DragEnter
事件=>是的!另一方面,移动部分仅在我释放鼠标后才起作用,导致控件永远挂在鼠标指针上=> 反是!
问题是:有没有办法同时进行两个操作?这样我就可以移动我的控件,像现在一样在每个位置抓住它,并在到达另一个控件的那个区域时触发DragEnter
事件?
移动控件会干扰自动拖放处理。
我建议保持正常的 DragDrop 过程,即将所有视觉对象留给系统:它将显示一个光标,指示何时输入有效目标,然后更改为指示操作的光标。
您只需要 3 行,没有麻烦,用户不会看到笨重的控件四处移动。
下面是我将图片框拖到列表框上的版本:
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
listBox1.Items.Add( e.Data.GetData(DataFormats.Text));
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
pictureBox1.DoDragDrop(pictureBox1.ImageLocation, DragDropEffects.Copy);
}
显然,您将以自己的方式设置和接收数据。
编辑:现在,另一方面,如果您需要移动控件以重新排列它们,也许您应该放弃拖放来处理额外的数据传输并自行编写此部分。您可以使用接收控件的MouseEnter
事件。
经过一番摆弄,我做到了。我切换了处理拖动的级别。
首先我只需要MouseDown
事件
public Point GrabPoint;
private void GeneralMouseDown(MouseEventArgs e)
{
GrabPoint = e.Location;
this.DoDragDrop(this, DragDropEffects.Move);
}
我设置了获取控件并启动拖放的位置。在我的表格上,我处理所有拖动:
private void frmMain_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl1)) || e.Data.GetDataPresent(typeof(MyControl2)) || e.Data.GetDataPresent(typeof(MyControl3)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void frmMain_DragOver(object sender, DragEventArgs e)
{
Point DragTarget = new Point(e.X, e.Y);
Point GrabPoint = new Point(0, 0);
if (e.Data.GetDataPresent(typeof(MyControl1)))
GrabPoint = ((MyControl1)e.Data.GetData(typeof(MyControl1))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
GrabPoint = ((MyControl2)e.Data.GetData(typeof(MyControl2))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
GrabPoint = ((MyControl3)e.Data.GetData(typeof(MyControl3))).GrabPoint;
DragTarget.X -= GrabPoint.X;
DragTarget.Y -= GrabPoint.Y;
DragTarget = this.PointToClient(DragTarget);
if (e.Data.GetDataPresent(typeof(MyControl1)))
((MyControl1)e.Data.GetData(typeof(MyControl1))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
((MyControl2)e.Data.GetData(typeof(MyControl2))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
((MyControl3)e.Data.GetData(typeof(MyControl3))).Location = DragTarget;
}
目前我不需要 DragDrop
-事件,因为当窗体上删除任何控件时,什么都不会发生。这样,我总是在拖动控件时绘制控件=>是的!
下一部分很简单:由于我实际上是在拖动控件,因此这段代码在我的列表框上进行了拖放处理 编辑: ListView
:
private void lst_SubControls_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl2)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void lst_SubControls_DragDrop(object sender, DragEventArgs e)
{
lst_SubControls.Items.Add(((MyControl2)e.Data.GetData(typeof(MyControl2))).SpecificDrive);
((MyControl2)e.Data.GetData(typeof(MyControl2))).DeleteThisControl();
}
这会导致将条目添加到列表中并删除拖动的控件。此时可能会进行检查,是否按 ctrl 键复制内容而不是删除控件。