Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / October 2007

Tip: Looking for answers? Try searching our database.

Event or other?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Steve - 13 Sep 2007 20:36 GMT
Hi All,

I'm a newbee in C# and have a Windows form application.  The main form
has a progress bar.  In one of the methods of the main form, I call a
class derived from Object which processes a file.  During the
processing, I'd like the custom class to be able to update the
progress bar.  

What's the best way to make this happen?  I've been reading up on
events/delegates and am beginning to get a vague understanding, but I
wanted to make sure I'm not going down the wrong path.

Thanks for any suggestions/insight,
Steve
Ignacio Machin ( .NET/ C# MVP ) - 13 Sep 2007 21:05 GMT
Hi,

> Hi All,
>
[quoted text clipped - 7 lines]
> events/delegates and am beginning to get a vague understanding, but I
> wanted to make sure I'm not going down the wrong path.

You have to use a thread to perform the operation and in the meantime in the
UI thread the progress bar is running.
Take a look at Control.Invoke as the way to communication between the worker
thread and the UI
Steve - 13 Sep 2007 21:12 GMT
On Thu, 13 Sep 2007 16:05:20 -0400, "Ignacio Machin \( .NET/ C# MVP
\)" <machin TA laceupsolutions.com> wrote:

>Hi,
>
[quoted text clipped - 14 lines]
>Take a look at Control.Invoke as the way to communication between the worker
>thread and the UI

I'd like to avoid multi-threading if I can.  I have no experience in
managing threads and it doesn't seem like it should be that
complicated to just reference a component on a form.
Ignacio Machin ( .NET/ C# MVP ) - 13 Sep 2007 21:22 GMT
Hi,

> On Thu, 13 Sep 2007 16:05:20 -0400, "Ignacio Machin \( .NET/ C# MVP
> \)" <machin TA laceupsolutions.com> wrote:
[quoted text clipped - 23 lines]
> managing threads and it doesn't seem like it should be that
> complicated to just reference a component on a form.

It's not complicated, besides if you never start you will never learn :)

See the other post in this thread as well as in the archives, a solution to
your problem is posted or discussed at least once a week
Morten Wennevik [C# MVP] - 13 Sep 2007 21:14 GMT
> Hi All,
>
[quoted text clipped - 10 lines]
> Thanks for any suggestions/insight,
> Steve

Hi Steve

An event should work fine here, but you also need to start your processing in a BackgroundWorker or another thread or the main thread won't get time to process the event.  And since the event will get caught in a thread other than the main thread, you need to use Invoke as well.  The sample below might give you some ideas.  If you don't mind having the class call the form directly (which isn't really good OO practice, you can skip throwing the event and call the form directly)

    public class MyForm : Form
    {

        <...>

        delegate void ProgressBarDelegate(int value);
        BackgroundWorker worker = new BackgroundWorker();
        MyClass myClass = new MyClass();

        private void Method()
        {
            myClass.MyEvent += new MyClass.MyEventHandler(myClass_MyEvent);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerAsync();
        }

        void myClass_MyEvent(int value)
        {
            if (progressBar1.InvokeRequired)
                progressBar1.Invoke(new ProgressBarDelegate(myClass_MyEvent), new object[] { value });
            else
                progressBar1.Value = value / 2;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            myClass.Method();
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("Done");
        }
    }

    public class MyClass
    {
        public event MyEventHandler MyEvent;
        public delegate void MyEventHandler(int value);

        public void Method()
        {
            for (int i = 0; i < 200; i++)
            {
                System.Threading.Thread.Sleep(200);
                MyEvent(i);
            }
        }
    }

Signature

Happy coding!
Morten Wennevik [C# MVP]

Andy C - 17 Oct 2007 09:53 GMT
> > Hi All,
> >
[quoted text clipped - 65 lines]
>          }
>      }

Hi Morten,

Thanks for the reply very useful. The only problem I get whilst running that
code is when I get to the  MyEvent(i); call in public void Method() I get a
NullReferenceException with "Object reference not set to an instance of an
object". Any idea what I'm doing wrong?

Cheers,

Andy
Marc Gravell - 17 Oct 2007 10:29 GMT
That means that nobody is listening to your event; a minor nuicance,
but you need to check events for null; this is usually done in an "On"
method, i.e. (given your unusual event signature):

protected virtual void OnMyEvent(int value) {
 MyEventHandler handler = MyEvent;
 if(handler!=null) handler(value);
}

and then call OnMyEvent(i); instead of MyEvent(i);

For a lazy implementation, you could just use:
if(MyEvent!=null) {MyEvent(i);}
but there are a few subtle issues that make the OnMyEvent the
recommended approach.

Marc
Andy C - 17 Oct 2007 11:27 GMT
> That means that nobody is listening to your event; a minor nuicance,
> but you need to check events for null; this is usually done in an "On"
[quoted text clipped - 13 lines]
>
> Marc

Hi Marc,

Thanks for the reply - I'm obviously not doing something right;

In my form I have:-

delegate void ProgressBarDelegate(int value);
BackgroundWorker worker = new BackgroundWorker();

TryClass myClass = new TryClass();
private void Method()
       {
           myClass.MyEvent += new TryClass.MyEventHandler(myClass_MyEvent);
           worker.DoWork += new DoWorkEventHandler(worker_DoWork);
           worker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
           worker.RunWorkerAsync();
           }

       void myClass_MyEvent(int value)
       {
           if (prgStatus.InvokeRequired)
               prgStatus.Invoke(new ProgressBarDelegate(myClass_MyEvent),
new object[] { value });
           else
               prgStatus.Value = value / 2;
       }

       void worker_DoWork(object sender, DoWorkEventArgs e)
       {
           myClass.Method();
       }

       void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
       {
           MessageBox.Show("Done");
       }

In the class I have :-

       public event MyEventHandler MyEvent;
       public delegate void MyEventHandler(int value);

       public void Method()
       {
           for (int i = 0; i < 100; i++)
           {
               System.Threading.Thread.Sleep(200);

               if (MyEvent != null)
               { MyEvent(i); }

           }
       }

I am then calling the method from another class in the same project;

           TryClass x = new TryClass ();
           x.Method();

All I seem to get are null values in the MyEvent(i) - any ideas what I am
doing wrong? It's like the MyEvent doesn't connect back to the form.

Thanks,

Andy
Marc Gravell - 17 Oct 2007 12:00 GMT
> All I seem to get are null values in the MyEvent(i)
Sorry - can you clarify what you mean? is MyEvent null? Or is
something throwing an exception?

Note that with BackgroundWorker, a better way to handle the updates is
to set WorkerReportsProgress = true, and then from your loop call
ReportProgress(value). You can then catch the ProgressChanged event
(which is fired on the UI thread, so no InvokeRequired / Invoke) and
get the value from the event-arg.

Marc
Peter Duniho - 17 Oct 2007 18:20 GMT
> Thanks for the reply - I'm obviously not doing something right;

Correct. :)

> In my form I have:-
>
> delegate void ProgressBarDelegate(int value);
> BackgroundWorker worker = new BackgroundWorker();
>
> TryClass myClass = new TryClass();

So, in your form, you've created an instance of TryClass() and subscribe
your event handler to the event in that instance.

> [...]
> I am then calling the method from another class in the same project;
>
>             TryClass x = new TryClass ();

And then within your background worker thread, you create a new instance
of TryClass().

>             x.Method();

And then call the method that raises the event using that new instance,
rather than the instance in which you subscribed your handler.

> All I seem to get are null values in the MyEvent(i) - any ideas what I am
> doing wrong? It's like the MyEvent doesn't connect back to the form.

You are creating a new instance of TryClass.  That instance is not the
same one to which you subscribed your event handler, so of course the
event in that instance isn't subscribed.

You need to create just one instance of the class, and then use that
instance when executing the method of interest.  Alternatively (and this
comes up more often than one might think) if you can genuinely get away
with creating a new instance each time you want to call the method, then
that method shouldn't be an instance method anyway as you're obviously
not using anything that is unique per-instance.

In this alternative case, just make the method and the event static.
And of course, if you have no other instance members in the class, then
the class itself could be static.

Pete
Andy C - 18 Oct 2007 15:00 GMT
> > Thanks for the reply - I'm obviously not doing something right;
>
[quoted text clipped - 42 lines]
>
> Pete

Hi Peter,

Thanks for the reply - I think I'm nearly there now. I made the class static
but I'm still getting nothing but null values.

In the class I have;

   public static class TryClass
   {
       public static event MyEventHandler MyEvent;

       public delegate void MyEventHandler(int value);

       public static void Method()
       {
           for (int i = 0; i < 100; i++)
           {
               System.Threading.Thread.Sleep(200);

               if (MyEvent != null)
               { MyEvent(i); }

           }
       }      

In the form I have;

 delegate void ProgressBarDelegate(int value);
       BackgroundWorker worker = new BackgroundWorker();
       
       private void Method()
           {
           TryClass.MyEvent += new TryClass.MyEventHandler(TryClass_MyEvent);
           worker.DoWork += new DoWorkEventHandler(worker_DoWork);
           worker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
           worker.RunWorkerAsync();
           }

       void TryClass_MyEvent(int value)
       {
           if (prgStatus.InvokeRequired)
               prgStatus.Invoke(new ProgressBarDelegate(TryClass_MyEvent),
new object[] { value });
           else
               prgStatus.Value = value / 2;
       }
       void worker_DoWork(object sender, DoWorkEventArgs e)
       {
           TryClass.Method();
       }

       void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
       {
           MessageBox.Show("Done");
       }

I'm now calling TryClass.Method(); and I'm still getting nothing but null
values.

Thanks,

Andrew
Peter Duniho - 18 Oct 2007 17:53 GMT
> [...]
> I'm now calling TryClass.Method(); and I'm still getting nothing but null
> values.

Well, maybe I'm just overlooking something, but I didn't see anything
obviously wrong in the code you posted (other than the fact that you
don't unsubscribe from the event after you're done with it, but that
won't affect whether you can be called when the event is raised).

If no one else catches the error, you should post a concise-but-complete
example of code that demonstrates the problem.  Assuming I didn't miss
anything, the fact that it's still not working means that there's
something in the code you didn't post that's causing a problem.

Having a concise-but-complete code example would allow anyone to just
compile the thing and test it themselves.  Since there's nothing about
what you're trying to do that requires a form, the code you post should
actually be a console application.  Yes, this means you need to
basically write a new code sample, copying the important bits from the
code that already exists.

Of course, that assumes the code you posted is exactly the code you're
using.  If it's not strictly a copy-and-paste from your program, that's
obviously going to prevent anyone from saying what's wrong with the code
you're actually using.  :)

Pete
Andy C - 19 Oct 2007 15:29 GMT
Many thanks - I got it to work. It helps if you actually call the event in
the first place. Doh!

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.