winforms 如何使foreach循环中的第二个if语句中的代码只运行一次?

kzipqqlq  于 2023-02-13  发布在  其他
关注(0)|答案(1)|浏览(126)

我有这个foreach循环来迭代窗体中的控件,这样我就可以找到我用箭头键移动的picturebox,并检查它是否通过标记与其他picturebox冲突。现在我想检查picturebox是否与带有标记“portal”的picturebox冲突,如果是,它必须打开一个新窗体并关闭/隐藏当前窗体,我做到了,而且运行良好,唯一的问题是它打开第二个表单13次,我想这是因为它运行了13次foreach循环,运行了13次那3行代码,但我希望它们只运行一次,打开新表单,关闭/隐藏当前表单一次。

private void moveTimerEvent(object sender, EventArgs e)
        {
            if (moveLeft == true && pictureBox1.Left > 10)
            {
                pictureBox1.Left -= speed;
            }
            if (moveRight == true && pictureBox1.Left < 1850) //right border of the screen.
            {
                pictureBox1.Left += speed;
            }
            if (moveUp == true && pictureBox1.Top > 10)
            {
                pictureBox1.Top -= speed;
            }
            if (moveDown == true && pictureBox1.Top < 962) //bottom border of the screen.
            {
                pictureBox1.Top += speed;
            }
            foreach (Control x in this.Controls) //foreach loop that I am referring to
            {
                if (x is PictureBox && (string)x.Tag == "wall")
                {
                    if (pictureBox1.Bounds.IntersectsWith(x.Bounds))
                    {
                        pictureBox1.Location = new Point(123, 962);
                    }
                }
                else
                {
                    if (x is PictureBox && (string)x.Tag == "portal") //if statement that I am also referring to
                    {
                        if (pictureBox1.Bounds.IntersectsWith(x.Bounds)) //if statement that runs 13 times, but only has to run once
                        {
                            Form2 f2 = new Form2(); //open form2
                            f2.Show(); //show it
                            this.Hide(); //close this one
                        }
                    }
                }
            }
        }

我试着在我只想运行一次的代码后面添加一个break,但它仍然打开了新窗体13次。我希望break只运行一次,然后停止运行那些行。

qeeaahzv

qeeaahzv1#

你的帖子描述了你在代码中显示的定时器方案和内部循环中遇到的一些问题。但是你的实际目标是什么呢?你在帖子中说它的 * 存在理由 * 是:
[...]这样我就可以找到我用箭头键移动的图片框,并通过标签检查它是否与其他图片框冲突。
这"可能"被认为是X-Y Problem,因为可能有比定时器更优的方式来实现您最初想要做的事情(因为间隔为20ms的定时器可能会出现一些竞争条件,使其难以按预期启动和停止)。

    • 箭头键图片框**

考虑自定义PictureBox,当按下Left、Right、Up或Down时,它可以MoveProgrammatically(Keys direction)。它还需要根据IsCurrentMoveTarget属性跟踪这个"特定"图片框是否是应该移动的那个。当它"确实"成为当前移动目标时,它会通知所有"其他"示例它们不再是。

class ArrowKeyPictureBox : PictureBox
{
    public ArrowKeyPictureBox() 
    {
        LostFocus += (sender, e) =>Refresh();
        GotFocus += (sender, e) =>Refresh();
        MouseDown += (sender, e) =>
        {
            Focus();
            foreach (var control in Parent.Controls.OfType<ArrowKeyPictureBox>())
            {
                if (!ReferenceEquals(control, this)) control.IsCurrentMoveTarget = false;
            }
            IsCurrentMoveTarget = true;
        };
        Paint += (sender, e) =>
        {
            if (Focused && IsCurrentMoveTarget) using (var pen = new Pen(Color.Fuchsia))
                {
                    var rect = new Rectangle(
                        e.ClipRectangle.Location,
                        new Size(
                            (int)(e.ClipRectangle.Width - pen.Width),
                            (int)(e.ClipRectangle.Height - pen.Width)));
                    e.Graphics.DrawRectangle(pen, rect);
                }
        };
    }

Move方法具有碰撞检测功能,并在即将发生时激发一个可取消事件。

const int INCREMENT = 1;
    public void MoveProgrammatically(Keys direction)
    {
        Rectangle preview = Bounds;
        if (IsCurrentMoveTarget)
        {
            BringToFront();
            switch (direction)
            {
                case Keys.Up:
                    if (Top <= 0)
                    {
                        return;
                    }
                    preview.Y -= INCREMENT;
                    if(detectCollision())
                    {
                        return;
                    }
                    Top = preview.Y;
                    break;
                case Keys.Down:
                    if (Bottom >= Parent.Bottom)
                    {
                        return;
                    }
                    preview.Y += INCREMENT;
                    if (detectCollision())
                    {
                        return;
                    }
                    Top = preview.Y;
                    break;
                case Keys.Left:
                    if (Left <= 0)
                    {
                        return;
                    }
                    preview.X -= INCREMENT;
                    if (detectCollision())
                    {
                        return;
                    }
                    Left = preview.X;
                    break;
                case Keys.Right:
                    if (Right >= Parent.Right)
                    {
                        return;
                    }
                    preview.X += INCREMENT;
                    if (detectCollision())
                    {
                        return;
                    }
                    Left = preview.X;
                    break;
            }
        }
        bool detectCollision()
        {
            foreach (Control control in Parent.Controls)
            {
                if(!ReferenceEquals(this, control))
                {
                    if(preview.IntersectsWith(control.Bounds))
                    {
                        var e = new CollisionDetectedEventArgs(control: control);
                        CollisionDetected?.Invoke(this, e);
                        return !e.Cancel;
                    }
                }
            }
            return false;
        }
    }
    public static event CollisionDetectedEventHandler CollisionDetected;

确定这是否是要移动的控件,以及是否绘制聚焦框。

public bool IsCurrentMoveTarget
    {
        get => _isCurrentMoveTarget;
        set
        {
            if (!Equals(_isCurrentMoveTarget, value))
            {
                _isCurrentMoveTarget = value;
                Refresh();
            }
        }
    }
    bool _isCurrentMoveTarget = false;
}
    • 主窗体**

主窗体使用MessageFilter表示Up Down Left Right键事件,并将任何事件广播到它可能包含的所有ArrowKeyPictureBox示例。

public partial class MainForm : Form , IMessageFilter
{
    public MainForm()
    {
        InitializeComponent();
        Application.AddMessageFilter(this);
        Disposed += (sender, e) => Application.RemoveMessageFilter(this);
        ArrowKeyPictureBox.CollisionDetected += onAnyCollisionDetected;
    }

    const int WM_KEYDOWN = 0x0100;
    public bool PreFilterMessage(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_KEYDOWN:
                if (Controls.OfType<ArrowKeyPictureBox>().Any(_ => _.Focused))
                {
                    Keys key = (Keys)m.WParam;
                    switch (key)
                    {
                        case Keys.Up:
                        case Keys.Down:
                        case Keys.Left:
                        case Keys.Right:
                            BeginInvoke(new Action(() =>
                            {
                                foreach (var target in Controls.OfType<ArrowKeyPictureBox>())
                                {
                                    target.MoveProgrammatically(key);
                                }
                            }));
                            // Suppress OS tabbing to prevent loss of focus.
                            return true;
                    }
                }
                break;
        }
        return false;
    }

显示碰撞状态:

private void onAnyCollisionDetected(object sender, CollisionDetectedEventArgs e)
    {
        e.Cancel = !e.Control.Name.Contains("Portal");
        if (sender is Control control)
        {
            if (!_prevWarning.Equals(control.Bounds))
            {
                richTextBox.SelectionFont = new Font(richTextBox.Font, FontStyle.Bold);
                richTextBox.SelectionColor = e.Cancel ? Color.Green : Color.Red;
                richTextBox.AppendText($"{Environment.NewLine}Collision{Environment.NewLine}");
                richTextBox.SelectionFont = new Font(richTextBox.Font, FontStyle.Regular);
                richTextBox.SelectionColor = Color.Black;

                List<string> builder = new List<string>();
                builder.Add($"Moving: {control.Name}");
                builder.Add($"@ {control.Bounds}");
                builder.Add($"Collided with: {e.Control.Name}");
                builder.Add($"@ {e.Control.Bounds}");
                richTextBox.AppendText($"{string.Join(Environment.NewLine, builder)}{Environment.NewLine}");
                richTextBox.ScrollToCaret();
                _prevWarning = control.Bounds;
            }
        }
    }
    Rectangle _prevWarning = new Rectangle();
}

相关问题