Search code examples
c#winformsmouseeventminesweeper

How to interrupt mouseUp-event, if control has changed


I have just finished a Minesweeper-game in Windows-Forms, which I did for practice.

Everything runs just fine, but I discovered, that if you click and hold a button, it will be unfolded, even if the mouse doesn't point to that button anymore.

Do you have a simple idea of how I could fix this?

The Code:

/// <summary>
/// Build up a new Gamefield with the number of buttons, the user has selected
/// </summary>
private void DrawGameField()
{
  _buttons = new Button[_xLength, _yLength];
  for (int yPos = 0; yPos < _yLength; yPos++)
  {
    for (int xPos = 0; xPos < _xLength; xPos++)
    {
      var btn = new Button()
      {
        Tag = new Point(xPos, yPos),
        Location = new Point(xPos * 30, yPos * 30),
        Size = new Size(30, 30),
      };

      _buttons[xPos, yPos] = (Button)btn;
      btn.MouseUp += btn_Click;
      _gamePanel.Controls.Add(btn);
    }
  }
}

/// <summary>
/// Is called when a field is left-clicked
/// </summary>
private void LeftMouseClick(object sender, MouseEventArgs e)
{
  var btn = sender as Button;
  Point pt = (Point)btn.Tag;

  // If there's already a flag on the field make it unclickable for left mouseclick
  if (btn.Image != null)
    return;

  _game.UnfoldAutomatically(pt.X, pt.Y);
  btn.Text = (_game.ReturnNumberInField(pt.X, pt.Y)).ToString();

  // If clicked field was not a bombfield
  if (btn.Text != "-1")
    UnfoldFields();

  else
    LooseGame();
}

Every button gets a mouseUp-event in the DrawGameField - Method. Every button also gets a Tag in that method, so it can be identified. LeftMouseClick is calles, as soon as the user (mouseUp)-clicks on one oft the gamefield-buttons.

I want to cancel that if the button on which the left mousebutton is released is different to the button, that was actually clicked on.

This should give the user the possibility, to change his mind...he might actually click on a field, then realizes, that he doesn't want to unfold that field, but in my solution he isn't able to undo his click yet....


Solution

  • Well Guys, with a little Help, I have the correct solution to the problem, which is as follows:

    Use "MouseClick" and not "MouseUp" or "MouseDown".

    Why?

    MouseClick internally uses MouseDown then performs MouseCapture (notices, which control was under the mousepointer and checks, whether the mouse was still pointing to that control) if true -> click event if false -> return

    The working code:

    /// <summary>
    /// Build up a new Gamefield with the number of buttons, the user has selected
    /// </summary>
    private void DrawGameField()
    {
      // _xLength is the length of the field in x-direction
      // _yLength is the length of the field in y-direction
      var buttons = new Button[_xLength, _yLength];
    
      // Filling the buttonArray
      for (int yPos = 0; yPos < _yLength; yPos++)
      {
        for (int xPos = 0; xPos < _xLength; xPos++)
        {
          var btn = new Button()
          {
            Tag = new Point(xPos, yPos),
            Location = new Point(xPos * 30, yPos * 30),
            Size = new Size(30, 30)
          };
          // Apply a clickEvent to every button
          btn.MouseClick += Button_MouseClick; //first change here: Use MouseClick!!!
          buttons[xPos, yPos] = btn;
        }
      }
      AddGameButtonsToPanel(buttons);
    }
    
    /// <summary>
    /// Adds Buttons to the gamepanel
    /// </summary>
    private void AddGameButtonsToPanel(Button[,] buttons)
    {
      _buttons = buttons;
      _gamePanel.SuspendLayout();
      try
      {
        foreach (var btn in buttons)
          _gamePanel.Controls.Add(btn);
      }
      finally
      {
        _gamePanel.ResumeLayout();
      }
    }
    
    /// <summary>
    /// Checks which mouse-button was clicked and calls the correct method for that button
    /// </summary>
    private void Button_MouseClick(object sender, MouseEventArgs e)
    {
      // If it is the firs time a button is clicked, the stopwatch is started
      if (_firstClick)
        StartStopWatch();
    
      var btn = sender as Button;
      Point pt = (Point)btn.Tag;
    
      if (e.Button == MouseButtons.Left)
        Button_LeftClick(btn, pt);
      else
        Button_RightClick(btn, pt);
    }