۱۳۸۷/۰۹/۰۸

تبديل پلاگين‌هاي jQuery‌ به كنترل‌هاي ASP.Net


امروز داشتم يك سري از پلاگين‌هاي jQuery را مرور مي‌كردم، مورد زير به نظرم واقعا حرفه‌اي اومد و كمبود آن هم در بين كنترل‌هاي استاندارد ASP.Net محسوس است:
Masked Input Plugin
استفاده از آن به صورت معمولي بسيار ساده است. فقط كافي است اسكريپت‌هاي jQuery و سپس اين افزونه به هدر صفحه اضافه شوند و بعد هم مطابق صفحه usage آن عمل كرد.
خيلي هم عالي! ولي اين شيوه‌ي متداول كار در ASP.Net نيست. آيا بهتر نيست اين مجموعه را تبديل به يك كنترل كنيم و از اين پس به سادگي با استفاده از Toolbox ويژوال استوديو آن‌را به صفحات اضافه كرده و بدون درگير شدن با دستكاري سورس html صفحه، از آن استفاده كنيم؟ به‌عبارتي ديگر يكبار بايد با جزئيات درگير شد، آنرا بسته بندي كرد و سپس بارها از آن استفاده نمود. (مفاهيم شيءگرايي)

براي اين‌كار، يك پروژه جديد ايجاد ASP.Net server control را آغاز نمائيد (به نام MaskedEditCtrl).



به صورت پيش فرض يك قالب استاندارد ايجاد خواهد شد كه كمي نياز به اصلاح دارد. نام كلاس را به MaskedEdit تغيير خواهيم داد و همچنين در قسمت ToolboxData نيز نام كنترل را به MaskedEdit ويرايش مي‌كنيم.
براي اينكه مجبور نشويم يك كنترل كاملا جديد را از صفر ايجاد كنيم، خواص و توانايي‌هاي اصلي اين كنترل را از TextBox استاندارد به ارث خواهيم برد. بنابراين تا اينجاي كار داريم:
namespace MaskedEditCtrl
{
[DefaultProperty("MaskFormula")]
[ToolboxData("<{0}:MaskedEdit runat=server></{0}:MaskedEdit>")]
[Description("MaskedEdit Control")]
public class MaskedEdit : TextBox

{

سپس بايد رويداد OnPreRender را تحريف (override) كرده و در آن همان اعمالي را كه هنگام افزودن اسكريپت‌ها به صورت دستي انجام مي‌داديم با برنامه نويسي پياده سازي كنيم. چند نكته ريز در اينجا وجود دارد كه در ادامه به آن‌ها اشاره خواهد شد.
از ASP.Net 2.0 به بعد، امكان قرار دادن فايل‌هاي اسكريپت و يا تصاوير همراه يك كنترل، درون فايل dll آن بدون نياز به توزيع مجزاي آنها به صورت WebResource مهيا شده است. براي اين منظور اسكريپت‌هاي jQuery و افزونه mask edit را به پروژه اضافه نمائيد. سپس به قسمت خواص آنها (هر دو اسكريپت) مراجعه كرده و build action آنها را به Embedded Resource تغيير دهيد (شكل زير):



از اين پس با كامپايل پروژه، اين فايل‌ها به صورت resource به dll ما اضافه خواهند شد. براي تست اين مورد مي‌توان به برنامه reflector مراجعه كرد (تصوير زير):



پس از افزودن مقدماتي اسكريپت‌ها و تعريف آنها به صورت resource ، بايد آنها را در فايل AssemblyInfo.cs پروژه نيز تعريف كرد (به صورت زير).

[assembly: WebResource("MaskedEditCtrl.jquery.min.js", "text/javascript")]
[assembly: WebResource("MaskedEditCtrl.jquery.maskedinput-1.1.4.pack.js", "text/javascript")]

نكته مهم: همانطور كه ملاحظه مي‌كنيد نام فضاي نام پروژه (namespace) بايد به ابتداي اسكريپت‌هاي معرفي شده اضافه شود.

پس از آن نوبت به افزودن اين اسكريپت‌ها به صورت خودكار در هنگام نمايش كنترل است. براي اين منظور داريم:
        protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);

//adding .js files
if (!Page.ClientScript.IsClientScriptIncludeRegistered("jquery_base"))
{
string scriptUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(),
"MaskedEditCtrl.jquery.min.js");
Page.ClientScript.RegisterClientScriptInclude("jquery_base", scriptUrl);
}

if (!Page.ClientScript.IsClientScriptIncludeRegistered("edit_ctrl"))
{
string scriptUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(),
"MaskedEditCtrl.jquery.maskedinput-1.1.4.pack.js");
Page.ClientScript.RegisterClientScriptInclude("edit_ctrl", scriptUrl);
}

if (!Page.ClientScript.IsStartupScriptRegistered("MaskStartup" + this.ID))
{
// Form the script to be registered at client side.
StringBuilder sbStartupScript = new StringBuilder();
sbStartupScript.AppendLine("jQuery(function($){");
sbStartupScript.AppendLine("$(\"#" + this.ClientID + "\").mask(\"" + MaskFormula + "\");");
sbStartupScript.AppendLine("});");
Page.ClientScript.RegisterStartupScript(typeof(Page),
"MaskStartup" + this.ID, sbStartupScript.ToString(), true);
}

}

همانطور كه ملاحظه مي‌كنيد، ابتدا WebResource دريافت شده و سپس به صفحه اضافه مي‌شود. در آخر مطابق راهنماي افزونه mask edit عمل شد. يعني اسكريپت مورد نظر را ساخته و به صفحه اضافه كرديم.

نكته جاوا اسكريپتي: علت استفاده از this.ClientID جهت معرفي نام كنترل جاري اين است كه هنگاميكه كنترل توسط يك master page رندر شود، ID آن توسط موتور ASP.Net كمي تغيير خواهد كرد. براي مثال myTextBox‌ به ctl00_ContentPlaceHolder1_myTextBox تبديل خواهد شد و اگر صرفا this.ID ذكر شده باشد ديگر دسترسي به آن توسط كدهاي جاوا اسكريپت مقدور نخواهد بود. بنابراين از ClientID جهت دريافت ID نهايي رندر شده توسط ASP.Net كمك مي‌گيريم.

در اينجا MaskFormula مقداري است كه هنگام افزودن كنترل به صفحه مي‌توان تعريف كرد.

[Description("MaskedEdit Formula such as 99/99/9999")]
[Bindable(true), Category("MaskedEdit"), DefaultValue(0)]
public string MaskFormula
{
get
{
if (ViewState["MaskFormula"] == null) ViewState["MaskFormula"] = "99/99/9999";
return (string)ViewState["MaskFormula"];
}
set { ViewState["MaskFormula"] = value; }

}

اين خاصيت public هنگام نمايش در Visual studio به شكل زير درخواهد آمد:



نكته مهم: در اينجا حتما بايد از view state جهت نگهداري مقدار اين خاصيت استفاده كرد تا در حين post back ها مقادير انتساب داده شده حفظ شوند.

اكنون پروژه را كامپايل كنيد. براي افزودن كنترل ايجاد شده به toolbox مي‌توان مطابق تصوير عمل كرد:



نكته: براي افزودن آيكون به كنترل (جهت نمايش در نوار ابزار) بايد: الف) تصوير مورد نظر از نوع bmp باشد با اندازه 16 در16 pixel . ب) بايد آنرا به پروژه افزود و build action آن را به Embedded Resource تغيير داد. سپس آنرا در فايل AssemblyInfo.cs پروژه نيز تعريف كرد (به صورت زير).

[assembly: System.Web.UI.WebResource("MaskedEditCtrl.MaskedEdit.bmp", "img/bmp")]

كنترل ما پس از افزوده شدن، شكل زير را خواهد داشت:


جهت دريافت سورس كامل و فايل بايناري اين كنترل، اينجا كليك كنيد.