title: AjaxControlToolkit is undefined - Error when bringing an extender up to date
body: <p>I am looking for some way to warn the user if a form is 'dirty' and they try and navigate away from it.</p>
  
  <p><a href="http://www.codeproject.com/KB/ajax/ajaxdirtypanelextender.aspx" rel="nofollow">This project</a> seemed to do exactly what I needed.</p>
  
  <p>However, it was written back in 2007, and when I tried to use it "as-is" in my .NET 4.0 app with the latest version of the Ajax Control Toolkit it didn't work.</p>
  
  <p>So, I downloaded the source (<a href="http://www.codeproject.com/KB/ajax/ajaxdirtypanelextender/DirtyPanelExtenderSource.zip" rel="nofollow">available from the CodeProject article</a>) and tried to bring it up-to-date. But this is the first time I've attempted such a task and I'm a bit lost.</p>
  
  <p>The error I'm now getting is as follows:<br>
  <strong>Microsoft JScript runtime error: 'AjaxControlToolkit' is undefined</strong></p>
  
  <p>The line in the DirtyPanelExtenderBehaviour.js which gives the error is:
  <code>DirtyPanelExtender.DirtyPanelExtenderBehavior.registerClass('DirtyPanelExtender.DirtyPanelExtenderBehavior', AjaxControlToolkit.BehaviorBase);</code></p>
  
  <p>Here's what I've done so far:<br>
  1. Downloaded the source from the Codeproject article<br>
  2. Opened in Visual Studio 2010 and completed the upgrade wizard<br>
  3. Deleted references to AjaxControlToolkit.dll and replaced with a new reference to the latest version of the toolkit
  4. Amended references to <code>ScriptManager</code> with <code>ToolkitScriptManager</code> (Not sure if this was needed)<br>
  5. Amended the sample website to use a <code>ToolkitScriptManager</code> on the page in place of a <code>ScriptManager</code></p>
  
  <p>Sooo, any ideas what I've done wrong? Or what I'm missing? So that I can recompile the <code>DirtyPanelExtender.dll</code> and use it in my .NET 4.0 project?</p>
  
  <p>The full code is below that I am using. <a href="http://www.codeproject.com/KB/ajax/ajaxdirtypanelextender.aspx" rel="nofollow">The original author</a>  wrote this with exception of my amendments as detailed above - I'm not taking credit!</p>
  
  <p>DirtyPanelExtender.cs:</p>
  
  <pre><code>using System;
  using System.Web.UI.WebControls;
  using System.Web.UI;
  using System.ComponentModel;
  using System.ComponentModel.Design;
  using System.Collections.Generic;
  using System.Text;
  using AjaxControlToolkit;
  
  [assembly: System.Web.UI.WebResource("DirtyPanelExtender.DirtyPanelExtenderBehavior.js", "text/javascript")]
  
  namespace DirtyPanelExtender
  {
      [Designer(typeof(DirtyPanelExtenderDesigner))]
      [ClientScriptResource("DirtyPanelExtender.DirtyPanelExtenderBehavior", "DirtyPanelExtender.DirtyPanelExtenderBehavior.js")]
      [TargetControlType(typeof(Panel))]
      [TargetControlType(typeof(UpdatePanel))]
      public class DirtyPanelExtender : ExtenderControlBase
      {
          [ExtenderControlProperty]
          [DefaultValue("Data has not been saved.")]
          public string OnLeaveMessage
          {
              get
              {
                  return GetPropertyValue("OnLeaveMessage", "");
              }
              set
              {
                  SetPropertyValue("OnLeaveMessage", value);
              }
          }
  
          protected override void OnPreRender(EventArgs e)
          {
              string values_id = string.Format("{0}_Values", TargetControl.ClientID);
              string values = (Page.IsPostBack ? Page.Request.Form[values_id] : String.Join(",", GetValuesArray()));
              ToolkitScriptManager.RegisterHiddenField(this, values_id, values);
              base.OnPreRender(e);
          }
  
          private string[] GetValuesArray()
          {
              return GetValuesArray(TargetControl.Controls);
          }
  
          private string[] GetValuesArray(ControlCollection coll)
          {
              List&lt;string&gt; values = new List&lt;string&gt;();
              foreach (Control control in coll)
              {
                  if (control is RadioButtonList)
                  {
                      for (int i = 0; i &lt; ((RadioButtonList)control).Items.Count; i++)
                      {
                          values.Add(string.Format("{0}_{1}:{2}", control.ClientID, i, ((RadioButtonList)control).Items[i].Selected.ToString().ToLower()));
                      }
                  }
                  else if (control is ListControl)
                  {
                      StringBuilder data = new StringBuilder();
                      StringBuilder selection = new StringBuilder();
                      foreach (ListItem item in ((ListControl) control).Items)
                      {
                          data.AppendLine(item.Text);
                          selection.AppendLine(item.Selected.ToString().ToLower());
                      }
                      values.Add(string.Format("{0}:data:{1}", control.ClientID, Uri.EscapeDataString(data.ToString())));
                      values.Add(string.Format("{0}:selection:{1}", control.ClientID, Uri.EscapeDataString(selection.ToString())));
                  }
                  else if (control is IEditableTextControl)
                  {
                      values.Add(string.Format("{0}:{1}", control.ClientID, Uri.EscapeDataString(((IEditableTextControl)control).Text)));
                  }
                  else if (control is ICheckBoxControl)
                  {
                      values.Add(string.Format("{0}:{1}", control.ClientID, ((ICheckBoxControl)control).Checked.ToString().ToLower()));
                  }
  
                  values.AddRange(GetValuesArray(control.Controls));
              }
              return values.ToArray();
          }
  
          public void ResetDirtyFlag()
          {
              ToolkitScriptManager.RegisterClientScriptBlock(TargetControl, TargetControl.GetType(),
                  string.Format("{0}_Values_Update", TargetControl.ClientID), string.Format("document.getElementById('{0}').value = '{1}';",
                      string.Format("{0}_Values", TargetControl.ClientID), String.Join(",", GetValuesArray())), true);
          }
      }
  }
  </code></pre>
  
  <p>DirtyPanelExtenderBehaviour.js:</p>
  
  <pre><code>Type.registerNamespace('DirtyPanelExtender');
  
  DirtyPanelExtender.DirtyPanelExtenderBehavior = function(element) {
  
      DirtyPanelExtender.DirtyPanelExtenderBehavior.initializeBase(this, [element]);
      this._OnLeaveMessageValue = null;
  }
  
  DirtyPanelExtender.DirtyPanelExtenderBehavior.prototype = {
  
      isDirty : function() {
          var values_control = document.getElementById(this.get_element().id + "_Values");
          var values = values_control["value"].split(",");
          for (i in values) {
              var namevalue = values[i];
              var namevaluepair = namevalue.split(":");
              var name = namevaluepair[0];
              var value = (namevaluepair.length &gt; 1 ? namevaluepair[1] : "");
              var control = document.getElementById(name);
              if (control == null) continue;
              // alert(control.id + " -&gt; " + control.type);
              if (control.type == 'checkbox' || control.type == 'radio') {
                  var boolvalue = (value == "true" ? true : false);
                  if(control.checked != boolvalue) {
                      // alert("checkbox changed: " + control.checked + " vs. " + boolvalue);
                      return true;
                  }
              } else if (control.type == 'select-one' || control.type == 'select-multiple') {
                 if (namevaluepair.length &gt; 2) {
                     if ( control.options.length &gt; 0) {
                         // control is listbox
                         // there's data:value and selection:value
                         var code = value;
                         value = (namevaluepair.length &gt; 2 ? namevaluepair[2] : "");
                         var optionValues = "";
                         // concat all listbox items
                         for( var cnt = 0; cnt &lt; control.options.length; cnt++) {
                            if (code == 'data') {
                                optionValues += control.options[cnt].text;
                            } else if (code == 'selection') {
                                optionValues += control.options[cnt].selected;
                            }
                            optionValues += "\r\n";
                         }
                         if( encodeURIComponent(optionValues) != value ) {
                            // items in the listbox have changed
                            // alert("listbox " + code + " changed: " + encodeURIComponent(optionValues) + " vs. " + value);
                            return true;
                         }
                     }
                 } else if(control.selectedIndex != value) {
                     // alert("dropdown selection changed: " + control.selectedIndex + " vs. " + value);
                     return true;
                 }
              } else {
                  if(encodeURIComponent(control.value) != value) {
                      // alert("control " + control.type + " changed: " + control.value + " vs. " + value);
                      return true;
                  }
              }
          }
          return false;
      },
  
      initialize : function() {        
          DirtyPanelExtender.DirtyPanelExtenderBehavior.callBaseMethod(this, 'initialize');
          DirtyPanelExtender_dirtypanels[DirtyPanelExtender_dirtypanels.length] = this;
      },
  
      dispose : function() {
          DirtyPanelExtender.DirtyPanelExtenderBehavior.callBaseMethod(this, 'dispose');
      },
  
      get_OnLeaveMessage : function() {
          return this._OnLeaveMessageValue;
      },
  
      set_OnLeaveMessage : function(value) {
          this._OnLeaveMessageValue = value;
      }
  }
  
  DirtyPanelExtender.DirtyPanelExtenderBehavior.registerClass('DirtyPanelExtender.DirtyPanelExtenderBehavior', AjaxControlToolkit.BehaviorBase);
  
  var DirtyPanelExtender_dirtypanels = new Array()
  
  function DirtyPanelExtender_SuppressDirtyCheck()
  {
    window.onbeforeunload = null;
  }
  
  function __newDoPostBack(eventTarget, eventArgument) 
  { 
    // supress prompting on postback
    DirtyPanelExtender_SuppressDirtyCheck();
    return __savedDoPostBack (eventTarget, eventArgument);
  }
  
  var __savedDoPostBack = __doPostBack;
  __doPostBack = __newDoPostBack; 
  
  window.onbeforeunload = function (eventargs) 
  {
      for (i in DirtyPanelExtender_dirtypanels)
      {
          var panel = DirtyPanelExtender_dirtypanels[i];
          if (panel.isDirty()) 
          {
            if(! eventargs) eventargs = window.event;
            eventargs.returnValue = panel.get_OnLeaveMessage();
            break;
          }
      }
  }
  </code></pre>