locked
Just Plain Stuck: how do I define a custom event in Windows Forms, and make the form watch for it? RRS feed

  • Question

  • I just can't seem to get past this

    I have a windows form app that I did in a C# class, which just has 'Start' and 'Stop' buttons plus a list box.   Pressing Start causes a thread to be instantiated that writes out a status message every second, for ten seconds, then ends.   Pressing Stop causes the last thread started to exit.

    For my own educative purposes, I thought it would be a good idea to enhance the form so that it automatically detects when there are no threads running, and thereby enables or disables the Stop button accordingly, by changing the Enabled property.

    In the form I have (My code in bold):

    [code]
    namespace MoreThreads
    {
        partial class DisplayThreadDataForm
        {
            //NobodyWorkingListener nbwl;
            public delegate void NobodyWorkingDelegate(object obj, EventArgs e);
            public event NobodyWorkingDelegate NobodyWorkingEvent;

           
           
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

    [/code]
    and a little further down, inside InitializeComponent()
    [code]
                this.Enter += new System.EventHandler(this.DisplayThreadDataForm_Enter);
                this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.DisplayThreadDataForm_FormClosing);
                this.MouseHover += new System.EventHandler
                    (this.DisplayThreadDataForm_MouseHover);
                this.ResumeLayout(false);

                this.NobodyWorkingEvent +=
                    new NobodyWorkingDelegate(this.DisplayThreadForm_NobodyWorking);

            }
    [/code]

    Over in the other partial class definition for the form I have the event handler, as follows.
    [code]
            private void DisplayThreadForm_NobodyWorking
                (object sender, EventArgs e)
            {
                btnStop.Enabled = false;
            }

    [/code]

    Actually I've got two problems with this.  Although this does compile, I notice that it prevents the design view of the form from working, but I think that's probably just because I need to move my custom code from InitializeComponent() to the constructor following the invocation of that.

    Second, I just don't know how to trap the condition.   Threads are instantiated as members of a Worker class; Worker has a static running count of the number of Workers currently active, but how do I get the form to monitor it, and raise the event when necessary?




    • Edited by Pithecanthropus Friday, May 30, 2008 7:54 PM fixed title again
    • Moved by Peter Ritchie Monday, June 2, 2008 5:55 PM more appropriate forum
    Friday, May 30, 2008 7:50 PM

Answers

All replies

  • I'm guessing that you have a timer callback for writing out the status message and it would be easy to check from that whether any threads are running and disable the button when the thread count reaches zero.
    I don't see the need for having it defined in an event but if you're absolutely set on having it as a part of an event (for educational purposes, I'm guessing) I would do it something like this (pseudo code):

    Create a list of threads that inherits Generic List

    public class MyThreadList : List<T>
    {
        //define the remove method of the list
       public virtual void Remove(T item)
       {
              base.Remove(item);
              OnCheckStatus();
       }
       public event EventHandler<EventArgs> CheckStatus;
       public void OnCheckStatus()
       {
             if (CheckStatus != null)
                CheckStatus(this,EventArgs.Empty);
       }  
    }

    In your form initializer:

        MyThreadList myThreadList = new MyThreadList();
        myThreadList.CheckStatus += new CheckStatus<EventArgs>(CheckThreadStatus);

    Then in your BtnStart method:

        //Create the thread for checking
        

        //Add the thread to your list
        MyThreadList.Add(Thread);

    //The event method
    public void CheckThreadStatus(object sender, EventArgs e)
    {
          if ((MyThreadList)sender).Count == 0)
          {
                btnStop.Enabled = false;
          }
    }
     

    You could of course change the Remove method of the list to only raise the CheckStatus event when the list count reaches 0

    public virtual Remove(T item)
    {
        base.Remove(item);
        if (this.Count == 0)
            OnCheckStatus();
    }

    That way you don't need to check if the list has reached 0 and therefor don't have to typecast the sender.

    Hope it helps


    nisbus
    Friday, May 30, 2008 10:59 PM
  • I think I understand now. 

    What I need to do is check any place in the code where a thread stops processing, if there are still any threads active, and raise the event there.

    Alternatively, would it be good practice just to have a static method looping somewhere in the code, checking the thread count every second or so and raising the event as needed?   Of course there'd be some overhead with that, but isn't that how events have to be handled in some cases?
    Saturday, May 31, 2008 12:02 AM
  • I came up with a way that works.

    I use a Timer control, and check the worker count in the Tick event.

    If this were a real program I'd want to check it over to make sure my static count is accurate.   Or try to query the thread count as a collection, via LINQ.
    Saturday, May 31, 2008 2:52 AM
  • I would recommend using a threaded timer for that kind of back processing but I would also prefer to use events to save resources.
    If your thread count goes down to 0 once an hour for example and your timer is checking the status every second you will have 3600 checks that were unnecessary.

    nisbus
    Monday, June 2, 2008 9:10 AM
  • For questions and discussions relating to WinForms, please see http://forums.microsoft.com/msdn/ShowForum.aspx?ForumID=8&SiteID=1
    http://www.peterRitchie.com/blog
    Monday, June 2, 2008 5:55 PM