Question

I'm writing a simple input form using Model-View-Presenter, and I've encountered difficulty with handling the FormClosing event.

When dealing with a normal Form, it has an event that fires on closing called FormClosing that I can use to cancel the close if I deem it necessary. In this case, I'd like to cancel the form close if the input is bad. For instance:

public interface IView
{
  event EventHandler<CancelEventArgs> Closing;

  string Input { get; set; }
  string ErrorMessage { set; }
}

public class Presenter
{
  private IView view;

  public Presenter(IView view)
  {
    this.view = view;

    // bind to events
    view.Closing += view_Closing;
  }

  private void view_Closing(object sender, CancelEventArgs e)
  {
    e.Cancel = !ValidateInput();
  }

  private bool ValidateInput()
  {
    bool validationSuccessful = true;

    // perform validation on input, set false if validation fails
    return validationSuccessful;
  }
}

I created my own event handler (Closing) because my understanding of MVP states that utilizing anything in System.Windows.Forms is not a good idea (e.g. if someday I update my view to WPF). Thus, in the WinForms implementation, I pass the event forward, as such:

public partial class View : IView
{
  public event EventHandler<CancelEventArgs> Closing;

  public string Input { get { return textBoxInput.Text; } set { textBoxInput.Text = value; } }
  public string ErrorMessage { set { errorProvider.SetError(textBoxInput, value) ; } }

  public View()
  {
    InitializeComponent();
  }

  private void View_FormClosing(object sender, FormClosingEventArgs e)
  {
    if (Closing != null)
      Closing(this, new CancelEventArgs(e.Cancel));
  }
}

I've found that even though in my Presenter I tell e.Cancel to set to true when validation fails, it does not cause the form to cancel the close. I'm clearly doing something wrong here, but I'm not sure what the proper solution is.

Was it helpful?

Solution

I figured it out after experimenting with the solution in another StackOverflow question. I needed to create a new CancelEventArgs in the View as follows:

private void View_FormClosing(object sender, FormClosingEventArgs e)
{
  CancelEventArgs args = new CancelEventArgs();

  if (Closing != null)
    Closing(this, args);

  e.Cancel = args.Cancel;
}

args.Cancel properly updated after the Closing event was called, and successfully mapped the resultant boolean to e.Cancel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top