将多个元素激活事件作为一个

时间:2014-04-25 02:02:24

标签: c# winforms events

我有一个父控件(面板),它有几个子控件(可能只有标签)。

现在我想使用Drag and Drop,如果可能甚至悬停在父控件上的效果。如果我只将所需事件分配给父类,则如果孩子导致事件(例如,点击标签不会触发面板点击事件),处理程序将无法执行。

我尝试在一个完全覆盖面板的其他所有内容上添加一个大元素(从而捕获每个事件),但是由于Windows窗体不支持,因此您无法再看到子元素真正的透明度。

使所有这些元素表现得像关于事件和拖放的最简洁方法是什么?

2 个答案:

答案 0 :(得分:0)

因此我现在理解,你想在Panel中有多个控件,当你拖动Panel控件时,你希望它里面的所有东西都用面板移动?您将通过标准的拖放操作获得该功能:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        bool isMouseDown;
        Point lastPoint = new Point(0,0);

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            isMouseDown = true;
            lastPoint = e.Location;
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
            {
                panel1.Location = new Point(
                    (
                    panel1.Location.X + e.X) - lastPoint.X,
                    (panel1.Location.Y + e.Y) - lastPoint.Y);

                this.Update();
            }
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            isMouseDown = false;

        }
    }
}

void Form1_Load(object sender,EventArgs e) {

for(int i = 0; i < 5; i++)
{
    Label l = new Label();
    l.MouseDown += l.MouseDown;
    l.MouseMove += l.MouseMove;
    l.MouseUp += l.MouseUp;
    panel1.Controls.Add(l);
}

}
    void l_MouseDown(object sender,MouseEventArgs e)     {         isMouseDown = true;         lastPoint = e.Location;     }

void l_MouseMove(object sender, MouseEventArgs e)
{
    if (isMouseDown)
        {
            panel1.Location = new Point(
                (
                panel1.Location.X + e.X) - lastPoint.X,
                (panel1.Location.Y + e.Y) - lastPoint.Y);

        ((Label)sender).Location = new Point(((Label)sender).Location.X + e.X) - lastPoint.X, ((Label)sender).Location.Y + e.Y) - lastPoint.Y));

            this.Update();
        }
}

void l_MouseUp(object sender, MouseEventArgs e)
{
    isMouseDown = false;
}

将其粘贴到新的WinForms项目中,并将Panel抛出到表单上,并向其添加一些Label控件。当拖动面板时,我已经用面板电影测试了这个和所有内容。

答案 1 :(得分:0)

我以前做过这种事。我这样做的方法是使用微软的反应式框架来平滑处理来自多个控件的事件的所有艰苦工作,然后以简单的方式查询它们。

首先,您需要使用NuGet添加&#34; Rx-WinForms&#34;打包到您的项目,using System.Reactive.Linq;打包到您的代码。

然后,您可以在拖动和放大器中创建要激活的控件数组。下降:

        var controls = new Control[]
        {
            panel1, label1, label2, label3,
        };

现在,我们需要了解这些控件中的MouseMoveMouseDownMouseUp事件的时间。这就是Reactive Framework的用武之地。对于在所有控件上聚合的每个事件,我们需要三个IObservable<MouseEventArgs>

以下是代码:

        IObservable<MouseEventArgs> moves =
            controls
                .Select(c =>
                    Observable
                        .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                            h => c.MouseMove += h,
                            h => c.MouseMove -= h))
                .Merge()
                .Select(x => x.EventArgs);

        IObservable<MouseEventArgs> downs =
            controls
                .Select(c =>
                    Observable
                        .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                            h => c.MouseDown += h,
                            h => c.MouseDown -= h))
                .Merge()
                .Select(x => x.EventArgs);

        IObservable<MouseEventArgs> ups =
            controls
                .Select(c =>
                    Observable
                        .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                            h => c.MouseUp += h,
                            h => c.MouseUp -= h))
                .Merge()
                .Select(x => x.EventArgs);

这可能看起来像是一些令人讨厌的代码,但它使下一部分变得非常简单:

        IObservable<Point> deltas =
            from down in downs
            from move in moves.TakeUntil(ups)
            select new Point
            {
                X = move.X - down.X,
                Y = move.Y - down.Y
            };

基本上这就是&#34;当我把鼠标放下,然后鼠标移动直到我得到一个鼠标,然后给我相对坐标,其中鼠标现在被比较到鼠标向下的点发生&#34;

现在我可以订阅这个增量流并重新定位面板:

        IDisposable subscription =
            deltas
                .Subscribe(d =>
                {
                    panel1.SetBounds(
                        panel1.Location.X + d.X,
                        panel1.Location.Y + d.Y,
                        0,
                        0,
                        BoundsSpecified.Location);
                });

Reactive Framework为您处理事件的所有连接。您需要清理的只是在.Dispose()变量上调用subscription以完全分离所有事件处理程序。

一旦你了解了正在发生的事情,这种编码变得比标准事件处理程序方法简单得多。

另一个好处是所有代码都在一个方法中,很可能是你的&#34; Form_Load&#34;,所以你不会得到大量的意大利面。