CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Dec 2003
    Posts
    112

    Safe Handling of Timers

    I need to know if there is a safe way to handle timers in a Component.

    Specifically, I need to ensure the timer is stopped and destroyed.

    If I have a User Control:

    Code:
    class MyControl : UserControl
    {
      private Timer timer = new Timer();
    
      public MyControl()
      {
        ...
        timer.Start();
        ...
      } 
    }
    Now suppose that user control is placed into a form. I need to ensure that the timer gets stopped if the form containing the control is closed. How can I do that?
    Eggman
    Using: VS 2008 w. Net 3.5

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Safe Handling of Timers

    Handle the Form's OnClosed event.

  3. #3
    Join Date
    Dec 2003
    Posts
    112

    Re: Safe Handling of Timers

    Quote Originally Posted by Arjay
    Handle the Form's OnClosed event.
    The problem is that the timer is part of a User Control not a Form, so in the context where the timer exists, it doesn't know about the form.

    Unless I can do something like:

    this.ParentForm
    Eggman
    Using: VS 2008 w. Net 3.5

  4. #4
    Join Date
    Dec 2003
    Posts
    112

    Re: Safe Handling of Timers

    Okay, so using:

    Code:
    this.ParentForm.FormClosing += StopTimer;
    I am able to ensure the timer gets stopped. However, the issue now is that in order to attach this callback, I had to do a hack with a "runonce" variable in the timer loop. The problem is that everywhere I have tried to attach the StopTimer callback, the ParentForm is null because the control has not yet been attached to a form.

    What I need now is a way to know when the ParentForm is no longer null so that I can start the timer at that point and attach the callback.
    Eggman
    Using: VS 2008 w. Net 3.5

  5. #5
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Safe Handling of Timers

    Can't you create a StopTimer method in your user control and call that method from your form closing event?

    Code:
    private void MyParentForm_FormClosing( object sender, FormClosingEventArgs e )
    {
      myUserControl.StopTimer( );
    }
    Better yet, can you override the control's Dispose method and do it in there?

    Code:
    private void MyParentForm_FormClosing( object sender, FormClosingEventArgs e )
    {
      myUserControl.Dispose;
    }

  6. #6
    Join Date
    Mar 2008
    Posts
    72

    Re: Safe Handling of Timers

    Quote Originally Posted by Eggman002
    ...What I need now is a way to know when the ParentForm is no longer null so that I can start the timer at that point and attach the callback.
    Don't know if that's the best way to do it, but just override the ParentForm property, check for null in the setter, and attach the handler there.

    I think the Dispose method is cleaner, though.

  7. #7
    Join Date
    Dec 2003
    Posts
    112

    Re: Safe Handling of Timers

    Doing it on Dispose is fine, so long as I can ensure that the control is disposed. Simply closing the form does not seem to necessarily call the dispose method.

    I could call dispose from the parent OnFormClosing event, but of course I still run into the problem of ensuring the Parent is not null.
    Eggman
    Using: VS 2008 w. Net 3.5

  8. #8
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Safe Handling of Timers

    Dispose gets called when the GC kicks in, not when the form closes.

    You can ensure that Parent isn't null by creating your own constructor which requires the parent form to be passed in.

  9. #9
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Safe Handling of Timers

    You can ensure that Parent isn't null by creating your own constructor which requires the parent form to be passed in.
    If you do this and don't supply a default constructor then your user control won't work in the designer any more.

    You have to handle the parent changed events of all parents of the control until a parent is added which is a Form.

    Have a look at this code :

    Code:
    public class ParentFormClosingHandler
    {
        private Control _baseControl;
        private Form _form;
    
        public event FormClosingEventHandler Closing;
    
        public ParentFormClosingHandler(Control control)
        {
            ProcessControl(control);   
        }
    
        void _baseControl_ParentChanged(object sender, EventArgs e)
        {
            _baseControl.ParentChanged -= new EventHandler(_baseControl_ParentChanged);
    
            ProcessControl(_baseControl);
        }
    
        void _form_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (sender == _form)
            {
                OnFormClosing(e);
            }
        }
    
        protected virtual void OnFormClosing(FormClosingEventArgs e)
        {
            if (Closing != null)
            {
                Closing(_form, e);
            }
        }
    
        private void ProcessControl(Control control)
        {
            while (control.Parent != null)
            {
                control = control.Parent;
            }
    
            _form = control as Form;
    
            if (_form == null)
            {
                _baseControl = control;
                _baseControl.ParentChanged += new EventHandler(_baseControl_ParentChanged);
            }
            else
            {
                _form.FormClosing += new FormClosingEventHandler(_form_FormClosing);
            }
        }
    }
    You use it thus :

    Code:
    public class MyUserControl : UserControl
    {
        private ParentFormClosingHandler _formClosingHandler;
    
        public MyUserControl()
        {
            InitializeComponent();
            _formClosingHandler= new ParentFormClosingHandler(this);
            _formClosingHandler.Closing += new FormClosingEventHandler(_formClosingHandler_Closing);
        }
    
        private void _formClosingHandler_Closing(object sender, FormClosingEventArgs e)
        {
            // ....
        }
    }
    What happens is

    (1) The ParentFormClosingHandler hooks into the user control's parent changed event.
    (2) When this is fired, the control's parent is checked to see if it's a form.
    (3) If not then the control's parent's parent changed event is handled (an so on and so on until...)
    (4) If the parent is a form then this form's closing event is handled.

    Get the idea ?

    Darwen.
    Last edited by darwen; September 28th, 2008 at 03:06 PM.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  10. #10
    Join Date
    May 2007
    Posts
    1,546

    Re: Safe Handling of Timers

    Quote Originally Posted by Arjay
    Dispose gets called when the GC kicks in, not when the form closes
    Not true. The GC never calls dispose on any class. The GC will always call a destructor though. If a destructor has been defined in a class, it is guaranteed to be called (at some stage) before the object is garbage collected. You can make the destructor call the Dispose method if you want, which is what is generally done to ensure that unmanaged resources are always released.

    Ideally though, you'd call Dispose before losing the last reference to the object as you could be waiting minutes/hours/days for the destructor to be called.
    Last edited by Mutant_Fruit; September 28th, 2008 at 05:55 PM.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured