views:

140

answers:

3

EDIT: this is a winform application, sorry for the inconvenience

Disclaimer: this is an assignment we got in college, and I'm stuck over this particular section of code.

I have 2 solutions in Visual Studio 2008, one for a Form and one for a DLL which the form can use for functionality. The idea is to send HTML mails from the client, and to use the Delegate to confirm this.

One class of the DLL contains nothing else but a single Delegate:

namespace Console.Grand
{
    public delegate void ObserverDelegate(string info);
}

In a file called Delegate.cs

In the form, I have the following method which I will use for the Delegate:

private void Update(string info)
{
   this.logBox.Text += Environment.NewLine + info;
}

The logBox variable is a TextArea on the form.

On transmitting, the following occurs(BL stands for "Business Layer"):

BL_MailOut bm = new BL_MailOut(s1,ListViewAdresses());
ObserverDelegate deleg = new ObserverDelegate(Update);
bm.SendMail(deleg);

The BL_MailOut constructor looks like this(we're in the DLL now):

public BL_MailOut(StandardPage page, List<MailAddress> list)
{
    this.s = page;
    this.adresslist = new List<MailAddress>();
    foreach (MailAddress m in list)
    {
        this.adresslist.Add(m);
    }
}

And the method SendMail:

public void SendMail(ObserverDelegate deleg)
{
    IO_MailOut im = new IO_MailOut(s, adresslist, deleg);
    Thread t = new Thread(new ThreadStart(im.Send));
    t.Start();
}

And finally, we arrive at the method Send():

public void Send()
{
    SmtpClient sc;
    MailMessage msg;
    string info;
    foreach (MailAddress adress in this.list)
    {
        try
        {
            sc = new SmtpClient(HOST);
            msg = new MailMessage(SENDER, adress.Address);
            msg.IsBodyHtml = true;
            msg.Subject = "test";
            msg.Body = page.ToString();
            sc.Send(msg);
            info = "(" + DateTime.Now + ") MAIL SENT TO" + Environment.NewLine + adress.Address;
            deleg(info);
        }
    }

I do catch the needed errors, I just left that out here to save room.

When deleg(info); is reached, expected behavior would be that the textBox receives the needed text. However, it does not. The instance of the delegate is preserved and the compiler gives no error. I've read the material on the MSDN site on Delegates, but nothing there helped.

+1  A: 

I do something similar to this in my program...here is how I did it.

    public void setBoxText(string value)
    {
        if (InvokeRequired)
            Invoke(new SetTextDelegate(setBoxText), value);
        else
            statusBox.Text += value;
    }

    delegate void SetTextDelegate(string value); 

I then call setBoxText whenever I want to append text to the box.

Aaron
This may very well solve it; the explanation is that when the delegate is invoked, it is running on another thread than `logBox` was created on. It is not allowed to access controls from other threads than the one they were created on. I suspect that there is an `InvalidOperationException` thrown when `deleg(info)` is executed.
Fredrik Mörk
Thank you for the explanation.
Aaron
A: 

It could be a problem of threads: you are setting the Text value in a different thread.

This page has more info: http://www.yoda.arachsys.com/csharp/threads/winforms.shtml

Moron
+1  A: 

Your Update method on the form is performing a cross-thread operation, which is not allowed.

Change your Update method on the form to this

    private void Update(string info)
    {
     ObserverDelegate callBack =  new ObserverDelegate((x) =>
            {
                this.logBox.Text += Environment.NewLine + info;
            });             

        if (this.InvokeRequired)
            this.Invoke(callBack, info);
        else
          callBack(info);
    }
Stan R.
This solution means that the text box will *not* be updated if `Update` is invoked from the UI thread (since `InvokeRequired` will be `false`). I doubt this is the intended behavior.
Fredrik Mörk
I updated the code, but I wanted it to be a little different than the other answer :)
Stan R.
Well, it certainly worked, but I don't really understand the "(x) =>" thing.
WebDevHobo
@WebDevHobo, that is just a shorthand for creating an anonymous method. Google for Lambda expressions in C#
Stan R.