Alvin
Alvin

Reputation: 8499

Stop form from closing before getting response from SmtpClient.SendCompleted Event

I am using SmtpClient to sent out email. I create some function in Mail class:

private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
    // Get the unique identifier for this asynchronous operation.
    String token = (string)e.UserState;

    if (e.Cancelled)
    {
        MailStatus = Status.CANCEL;
        MailStatusMessage = token + " Send canceled.";
    }
    else if (e.Error != null)
    {
        MailStatus = Status.ERROR;
        MailStatusMessage = token + " " + e.Error.ToString();
    }
    else
    {
        MailStatus = Status.SENT;
        MailStatusMessage = "Mail sent.";
    }

    mailSent = true;
}

public void SentEmail()
{
    client = new SmtpClient(Host, Port);
    client.Credentials = new NetworkCredential(UserName, Password);
    MailAddress from = new MailAddress(MerchantEmail, MerchantName);
    MailAddress to = new MailAddress(CustomerEmail);
    MailMessage message = new MailMessage(from, to);
    message.Body = EmailSubjectTemplate();
    message.BodyEncoding = System.Text.Encoding.UTF8;
    message.Subject = EmailSubjectTemplate();
    message.SubjectEncoding = System.Text.Encoding.UTF8;

    client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);

    client.SendAsync(message, "Sending message.");

    message.Dispose();
}

In a form I call the function, before closing the form, but when waiting for the response from the SendCompletedCallback, the this.Close() will be executed:

Mail mail = new Mail();
mail.SentEmail();
this.Close();

How can I stop the form from closing before I get a response from SendCompletedCallback?

Upvotes: 2

Views: 1199

Answers (2)

Damith
Damith

Reputation: 63095

Option1

public class Mail 
{
    public delegate void MailSendComplete();
    public event MailSendComplete OnMailSendComplete;
    private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // your code 
        // finally call the complete event
        OnMailSendComplete();
    }

    public void SentEmail()
    {
        // your code 
    }
}

subscribe to this event from calling form as:

Mail m = new Mail();
m.OnMailSendComplete += new Mail.MailSendComplete(m_OnMailSendComplete);
m.SentEmail();

When you receive the complete event you can close the form void m_OnMailSendComplete() { this.Close(); }

Option 2

when you create Mail object you can pass current form reference to it

Mail mail = new Mail(this);

then at the end of SendCompletedCallback you can close the form

public class Mail 
{
    public Form form { get; set; }
    public Mail(Form  f)
    {
        form = f;
    }

    private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // your code 
        // finally close the form
        form.Close();
    }
}

Upvotes: 0

Steve
Steve

Reputation: 216313

There is little that you can do if your user decides to forcibly close its computer. (switch off, task kill or whatever).
However, you can wire the Form_Closing event and change the e.Cancel property inside the CloseEventArgs to true, perhaps with a messagebox informing your user of the pending operation.

First add to your Main form (or whatever you call it) a global var acting as a status flag:

private bool eMailSentPendingComplete = false;

then in your SentMail method add this line just after the client.SentAsync:

eMailSentPendingComplete = true;

reset it to false in the SendCompletedCallback
and in your Main Form wire the FormClosing event:

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if(eMailSentPendingComplete == true)
        {
             DialogResult dr = MessageBox.Show("Pending email, do you wish to close?", MEssageBoxButtons.YesNo);
             e.Cancel = (dr == DialogResult.Yes ? true : false);
        }
    }

also in the FormClosing event you can take a look to the property e.CloseReason for further optimizations.

Upvotes: 1

Related Questions