katit
katit

Reputation: 17915

When do I unsubscribe from events inside Custom Control

I'm creating custom control that contain multiple parts. Inside template creation I'm subscribing for different events like so:

public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.partAreaCode = this.GetTemplateChild(PartAreaCode) as TextBox;
            this.partExchange = this.GetTemplateChild(PartExchange) as TextBox;
            this.partSubscriber = this.GetTemplateChild(PartSubscriber) as TextBox;

            if (this.partAreaCode == null || this.partExchange == null || this.partSubscriber == null)
            {
                throw new NullReferenceException("Template part(s) not available");
            }

            this.partAreaCode.KeyDown += this.AreaKeyDown;
            this.partAreaCode.TextChanged += this.AreaTextChanged;

            this.partExchange.KeyDown += this.ExchangeKeyDown;
            this.partExchange.TextChanged += this.ExchangeTextChanged;

            this.partSubscriber.KeyDown += this.SubscriberKeyDown;

            // Template might be applied after dependency property set
            // lets refresh UI in this case
            this.UIFromValue();
        }

So, I wonder if I should unsubscribe from those events and if so - where and how?

Upvotes: 1

Views: 994

Answers (2)

AnthonyWJones
AnthonyWJones

Reputation: 189457

Well you've accepted an answer already and you may be able to get away that approach but its a too risky for my tastes. It assumes that OnApplyTemplate only ever gets called once. Potentially though your custom control may live a long time with OnApplyTemplate getting called more than once.

I'll outline here what hard-core control developers do, I'll just use one TextBox for brevity.

[TemplatePart(Name = MyControl.PartAreaCode, Type = typeof(TextBox))]
public partial class MyControl: Control
{
     public MyControl()
     {
          DefaultStyleKey = typeof(MyControl);
     }

     #region Template Part Names
     private const string PartAreaCode = "AreaCodeTextBox";
     #endregion

     #region internal TextBox AreaCodeTextBox

     private TextBox _AreaCodeTextBox;
     internal TextBox AreaCodeTextBox
     {
          get { return _AreaCodeTextBox; }
          set
          {
              if (_AreaCodeTextBox != null)
              {
                   _AreaCodeTextBox -= AreaCodeTextBox_KeyDown;
                   _AreaCodeTextBox -= AreaCodeTextBox_TextChanged;
              }

              _AreaCodeTextBox = value;

              if (_AreaCodeTextBox != null)
              {
                   _AreaCodeTextBox += AreaCodeTextBox_KeyDown;
                   _AreaCodeTextBox += AreaCodeTextBox_TextChanged;
              }
          }
     }

     #endregion

     public overide void OnApplyTemplate()
     {
          base.OnApplyTemplate();
          AreaCodeTextBox = GetTemplateChild(PartAreaCode) as TextBox;
     }

     #region Part Event Handlers
     // Your event handlers here
     #endregion
}

Yes I know that this looks like overkill but the code is boilerplate and we use regions to rollup the repeative stuff so we can inspect code that actually does something interesting without being concerned with the plumbing. With this one instance its easy to roll it out to multiple parts.

Upvotes: 3

dowhilefor
dowhilefor

Reputation: 11051

You don't have to. Because your PART elements are children of the event subscriber. If your main control gets garbage collected, so do your PART elements. A short example. Lets say you have 2 instances A and B ... A keeps a hard reference to B. If B is only hold in memory by the reference in A and A gets garbage collected so does B. You don't need to clear the reference in A first.

If for some reason you don't want events anymore while your element, with your PART child elements, lives you have to unsubsribe of course.

A Rule of thumb: Always unsubscribe events if the event owner lives longer than the subscriber.

Upvotes: 4

Related Questions