How to: class library write back to form

M

mickieparis

Hi, I’m new to programming and I have a 2-tier app. A form and a
class library. I know to call the class library I need to add a
reference to the class library project, add a Using statement and
instantiate the CL. In the CL I want to do some processing and update
a text box back in the form. How to update the form from the class
library?

Do I need to add a reference from the CL to the EXE project? And do I
need to instantiate the form to be able to update the textbox?

Thanks much!
MP
 
M

mickieparis

Also, just to be a little clearer, I'm not talking about returning a
value, I mean, in the class library in a loop I want to update a text
box on the form for each iteration thru the loop. Thanks!
 
F

Family Tree Mike

mickieparis said:
Hi, I’m new to programming and I have a 2-tier app. A form and a
class library. I know to call the class library I need to add a
reference to the class library project, add a Using statement and
instantiate the CL. In the CL I want to do some processing and update
a text box back in the form. How to update the form from the class
library?

Do I need to add a reference from the CL to the EXE project? And do I
need to instantiate the form to be able to update the textbox?

Thanks much!
MP
.

Your class should raise an event with messages as it processes things. What
ever the client is then, if it desires, can handle the events as needed.
This way, if you have a command line client, it can write the messages to a
console.out. If the client is a form, it can put the message in a label. If
the client is a service, then it may log the message to some log file.

In other words, never tie your class to a single client.

Mike
 
M

mickieparis

does it matter how frequently the event is raised? what if I need to
raise the event every second or even less??
 
J

Jeff Johnson

does it matter how frequently the event is raised? what if I need to
raise the event every second or even less??

Raising an event is really little more than calling a method.
 
J

Jeff Gaines

does it matter how frequently the event is raised? what if I need to
raise the event every second or even less??

If you write to a label or text box when handling the event you will need
to call Refresh() on the label/text box or it won't get updated until the
processing is finished.
It's probably best to experiment with frequency of calling the event.
 
F

Family Tree Mike

mickieparis said:
does it matter how frequently the event is raised? what if I need to
raise the event every second or even less??

.

It does not matter how frequently the class raises the event. The client,
if swamped with messages can choose to ignore some (ie, not update the
display). The class should be in charge of how frequently the updates are
sent, not the client.

By the way, I frequently have updates to a client on the same cpu going
every 250 ms, so 1 second or less updates is not overwhelming.

Mike
 
M

mickieparis

can someone point me to some code examples where a class library (dll)
is sending events to a form. I understand better when I read code.
Thanks!

MP
 
G

Gregory A. Beamer

Hi, I'm new to programming and I have a 2-tier app. A form and a
class library. I know to call the class library I need to add a
reference to the class library project, add a Using statement and
instantiate the CL. In the CL I want to do some processing and update
a text box back in the form. How to update the form from the class
library?

Do I need to add a reference from the CL to the EXE project? And do I
need to instantiate the form to be able to update the textbox?


The form controls the library. Don't try to create a loop where both are
controlling each other (if you can accomplish it at all).

You are going to one of two things:

If synchronous in nature, you call a CL routine, from the form, and then
take the answer and update in your form code.

If you want an asynchronous operations (so the class library can "tell
the form it is ready") then use events.

Peace and Grace,

--
Gregory A. Beamer (MVP)

Twitter: @gbworld
Blog: http://gregorybeamer.spaces.live.com

*******************************************
| Think outside the box! |
*******************************************
 
G

Gregory A. Beamer

Also, just to be a little clearer, I'm not talking about returning a
value, I mean, in the class library in a loop I want to update a text
box on the form for each iteration thru the loop. Thanks!

No, you don't want to do this. You think you do, but this is a disaster
waiting to happen.

You can add an event handler to the form that updates and then have the
CL fire off an event, but you don't want the library controlling the
form.

Peace and Grace,

--
Gregory A. Beamer (MVP)

Twitter: @gbworld
Blog: http://gregorybeamer.spaces.live.com

*******************************************
| Think outside the box! |
*******************************************
 
M

mickieparis

Gregory,
just to make sure we're on the same page...in the class library, while
in a loop, I want to fire off an event each time thru the loop and I
want the Form class to subscribe to that event and update the UIs on
the form. The CL won't be updating the UIs directly. This is ok
right?
 
F

Family Tree Mike

mickieparis said:
can someone point me to some code examples where a class library (dll)
is sending events to a form. I understand better when I read code.
Thanks!

MP

.

You need to stop thinking about the class sending events to a form. The
class is simply broadcasting an event. This is similar to a radio/tv station
broadcasting the signal. The radio or tv set somewhere else sets its intent
to listen for the event. The tv/radio station does not need to know that at
this moment, they need to send a program out to 57 homes. They just
broadcast it. That's how csharp events work.

Here is a link to a simple example that should get you started.

http://www.codeproject.com/KB/cs/simplesteventexample.aspx

Mike
 
P

Peter Duniho

Jeff said:
If you write to a label or text box when handling the event you will
need to call Refresh() on the label/text box or it won't get updated
until the processing is finished.

This is only true if one inappropriately runs the processing on the same
thread that owns the form.

Assuming a task that takes long enough to run that simply setting the
text of a Label won't be immediately apparent to the user, that task
should be run in a different thread (e.g. by using BackgroundWorker), so
that the UI remains responsive (including being able to immediately show
changes to controls in the UI).
It's probably best to experiment with frequency of calling the event.

I would say as a general rule, if the event happens less frequently than
ten or twenty times a second, it's probably fine to just update every
time the event occurs. At some point, however, the frequency of the
updates is not only faster than the updates can occur on-screen, they
are also faster than the user could even perceive them anyway.

Ten to twenty times per second is already in that ballpark, but not
frequent enough to cause a serious performance issue in most cases.
Updating much more frequently than that will cause a serious slowdown in
throughput and should be avoided for that reason.

Pete
 
J

Jeff Johnson

just to make sure we're on the same page...in the class library, while
in a loop, I want to fire off an event each time thru the loop and I
want the Form class to subscribe to that event and update the UIs on
the form. The CL won't be updating the UIs directly. This is ok
right?

It's not only okay, it's EXACTLY what you want.
 
P

Peter Duniho

mickieparis said:
can someone point me to some code examples where a class library (dll)
is sending events to a form. I understand better when I read code.

It will look just like any other class raising an event. See MSDN for
example:
http://msdn.microsoft.com/en-us/library/awbftdfh.aspx

The main thing that will be "special" about your particular
implementation is that, since the event handler is trying to update a
control, if you run the processing in a thread other than the main GUI
thread that owns that control (and you should do that if it's in any way
time-consuming), _and_ you don't use BackgroundWorker to run that
process, you will need to use the Control.Invoke() method to invoke the
code that will actually update the GUI.

If you do use BackgroundWorker, and you use the ProgressChanged event on
BackgroundWorker rather than writing your own (which of course would be
the main reason to use BackgroundWorker), then the event handler will
already be executing on the correct thread, and you can update the GUI
as you normally would.

Here's a short example, showing both the use of an event in a worker
class to pass strings back to the client as well as the use of
BackgroundWorker to simplify the cross-thread issues:

class Worker
{
// A dummy task that will take some time to present a sequence
// of strings to the client code
public void TimeConsumingTask()
{
string[] rgstr = { "One", "Two", "Three", "Four", "Five" };

foreach (string str in rgstr)
{
Thread.Sleep(1000);
ReportMessage(str);
}
}

// An event in the Worker class that client code can
// subscribed to in order to receive the strings
public event Action<string> ReportMessage = delegate { };
}

class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Worker worker = new Worker();
BackgroundWorker bw = new BackgroundWorker();

// This event handler is executed on the background thread,
// when we finally call BackgroundWorker.RunWorkerAsync()
bw.DoWork += (sender, e) =>
{
worker.TimeConsumingTask();
};

// This event handler is raised by the TimeConsumingTask()
// method and so is also executed on the background thread.
worker.ReportMessage += (str) =>
{
// The second argument passed to ReportProgress() will
// show up in the ProgressChangedEventArgs.UserState
// property.
bw.ReportProgress(0, str);
}

// This event handler is raised when the ReportProgress()
// method is called, with BackgroundWorker automatically
// ensuring that it's raised in the same thread where
// the BackgroundWorker instance was created (i.e. the
// thread that owns the Form1 instance and its controls,
// such as the "label1" Label instance).
bw.ProgressChanged += (sender, e) =>
{
label1.Text = (string)e.UserState;
}

// Start the background task running
bw.RunWorkerAsync();

// ...and then this method exits, allowing the main GUI
// thread to keep pumping messages, responding to user
// input and changes to the UI, such as changes to the
// Text property of a Label control
}
}

Note that while the above looks lengthy, most of that length is in comments.

One alternative to the above is to have the worker class manage its own
thread, in which case your "ReportMessage" event handler would need to
explicitly update the "label1.Text" property, using the Control.Invoke()
method:

worker.ReportMessage += (str) =>
{
label1.Invoke((MethodInvoker)delegate
{
label1.Text = str;
});
}

Another alternative would be for the worker thread code to actually be
in the Form1 class, rather than in a separate class. In this case, you
probably wouldn't bother with the ReportMessage event itself, instead
just directly doing the work the event handler for that event would have
done.

IMHO, the latter alternative is inferior and should be avoided. But it
can be done.

Pete
 
G

Gregory A. Beamer

just to make sure we're on the same page...in the class library, while
in a loop, I want to fire off an event each time thru the loop and I
want the Form class to subscribe to that event and update the UIs on
the form. The CL won't be updating the UIs directly. This is ok
right?

That is what you want. The UI, since it drives the process, should be
alerted when something changes and handle the changes itself. if you do
it any other way, you end up with too many chiefs and not enough indians
- so to speak.

Peace and Grace,

--
Gregory A. Beamer (MVP)

Twitter: @gbworld
Blog: http://gregorybeamer.spaces.live.com

*******************************************
| Think outside the box! |
*******************************************
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top