# برنامه نویسی با محصولات مایکروسافت > برنامه نویسی مبتنی بر Microsoft .Net Framework > مقالات مرتبط با Microsoft .Net Framework >  AJAX را بدون AJAX تجربه کنید!

## Behrouz_Rad

*توجه:
کلیه ی حقوق این مقاله متعلق به سایت www.barnamenevis.org می باشد.
استفاده از مطالب این مقاله منوط به ذکر نام منبع است.*

*فایل ضمیمه پروژه را از انتهای همین مقاله داونلود کنید.*

تا به حال در مورد تکنولوژی "AJAX" زیاد شنیدید. "AJAX" که از آن به عنوان "Remote Scripting" نیز یاد می شود اجازه ی اجرای دستورات بر روی سرور و برگشت نتایج بدون ارسال صفحه به سرور را میدهد.
کتابخانه ها و پروژه هایی از قبیل AJAX Library، Magic AJAX،  Anthemو Atlas برای تسهیل استفاده از این فناوری، تولید و در اختیار برنامه نویسان قرار گرفته است.
در این مقاله قصد بر آن نیست که به جزئیات این تکنولوژی و شرح نحوه ی عملکرد آن پرداخته شود بلکه هدف، معرفی امکان جدیدی است که ASP.NET 2.0 برای استفاده از این تکنولوژی در اختیار برنامه نویسان قرار داده است.
قبل از ادامه بحث بهتره با اصطلاحی که در این مقاله زیاد با اون سر و کار داریم آشنا بشیم.
Client Callback: ارسال درخواست از سمت کلاینت بدون PostBack صفحه، که موجب اجرای یک روال Server-Side و برگشت نتیجه میشود را ""Client Callback مینامیم.

مراحل کار:
1) بار اصلی کار بر عهده ی اینترفیس "ICallbackEventHandler" هست. در هر صفحه ی ASP.NET که قصد استفاده از Client Callback را دارید باید این اینترفیس را ایمپلمنت کنید.
نحوه ی ایمپلمنت کردن یک اینترفیس (این اینترفیس) در دات نت به شکل زیر است:

public  partial  class  CallbacksInAspNet : System.Web.UI.Page,  ICallbackEventHandler
{

   public string GetCallbackResult() 
   {

   }

   public void RaiseCallbackEvent(string eventArgument)
   {

   }

}

2) اینترفیس "ICallbackEventHandler" دو عضو دارد: "GetCallbackResult" و "RaiseCallbackEvent".
در مورد نقش و نحوه ی استفاده از این دو عضو در ادامه توضیح میدم.

3) نقش جاوا اسکریپت در Client Callbacks نقشی مهم و کلیدی است. برای ارسال درخواست و دریافت نتایج به/از سرور، نیاز به استفاده از جاوا اسکریپت است. خوشبختانه روال کار یکنواخت و ساده است و تنها با چند خط کدنویسی میتوان به نتیجه ی دلخواه رسید.

باید تابع جاوا اسکریپتی ایجاد کرد که وظیفه ی ارسال درخواست به سرور و دریافت نتیجه را انجام بده.
ابتدا باید اطلاعات لازم برای ایجاد این تابع را فراهم کنیم.
این کار از طریق متد ""GetCallbackEventReference کلاس ClientScript در روال Page_Load میسر است.

پارامترهای متد GetCallbackEventReference:
این متد چهار Overload دارد که معمولا از اولین Overload آن استفاده می شود.

*پارامتر control:*
کنترلی را مشخص می کند که Client Callback در بستر آن انجام می شود. این پارامتر معمولا به فرم جاری اشاره می کند.
*پارامتر argument:*
مقداری که از سمت کلاینت به سرور (پارامتر eventArgument متد RaiseCallbackEvent)  پاس داده می شود و سرور بر مبنای آن نتیجه را برگشت می دهد. توجه داشته باشید که این مقدار ممکن است وجود داشته یا نداشته باشد.
به عنوان مثال در حالتی که قصد بازیابی مقدار ساعت یا تاریخ را از سرور را داریم نیازی به پاس دادن مقداری به سرور نداریم اما اگر قصد ما نمایش اطلاعاتی در صفحه بر مبنای عبارتی خاص است، این پارامتر محتوی آن عبارت خاص است.
پس واضح است که متد RaiseCallbackEvent در حالتی که مقداری از جانب کلاینت به سرور منتقل نمی شود، کاربردی نخواهد داشت.
*پارامتر clientCallback:*
نام تابع جاوا اسکریپتی در سمت کلاینت که نتیجه پردازش درخواست را دریافت و بر مبنای آن وظیفه ی محوله را انجام می دهد. به عبارت دیگر، نتیجه ی پردازش به این تابع پاس داده می شود.
*پارامتر context:*
تابع جاوا اسکریپتی که قبل از ارسال درخواست به سرور، اجرا می شود. این تابع معمولا برای ارزیابی داده ها مورد استفاده قرار میگیرد.

پس از دادن اطلاعات کافی به متد فوق، حال زمان ایجاد تابع فرا رسیده.
از متد GetCallbackEventReference متوجه شدید که این متد دو پارامتر ورودی دارد که مقادیر خود را از سمت کلاینت می گیرند. پارامترهای argument و context.
پس تابع ما نیاز به دو پارامتر ورودی دارد.
بدنه ی این تابع نیز از طریق متد GetCallbackEventReference ایجاد می شود.
از متد "RegisterClientScriptBlock" کلاس ClientScript نیز به منظور ایجاد این  اسکریپت در سمت کلاینت استفاده می کنیم.
نام تابع جاوا اسکریپت خود را "DoServerAction" می گذاریم.
تمامی گفته های فوق را در قالب کد در ذیل مشاهده می کنید:

protected  void Page_Load(object sender, EventArgs e)

{
string CR_REF = ClientScript.GetCallbackEventReference(this, "myValue", "ReceiveDataFromServer", "validateF");

if (!ClientScript.IsClientScriptBlockRegistered("DoSe  rverAction"))
{
   string SERVER_SCRIPT = @" function DoServerAction(myValue,validateF) { " + CR_REF + "}";
   ClientScript.RegisterClientScriptBlock(this.GetTyp  e(), "DoServerAction", SERVER_SCRIPT, true);
}

}


پس از اجرای دستورات فوق، در صورتی که سورس صفحه را مشاهده کنید قسمتی را به شکل زیر خواهید دید:

<script type="text/javascript">
<!--
function DoServerAction (myValue,validateF) {WebForm_DoCallback('__Page',myValue,RecieveDataFr  omServer,validateF,null,false)}// -->
</script>

حال زمان پرداختن به دو عضو اینترفیس ICallbackEventHandler یعنی متدهای GetCallbackResult و RaiseCallbackEvent شده است.
متد RaiseCallbackEvent در زمان ایجاد Callback (فراخوانی تابع DoServerAction) فراخوانی می شود و همان طور که پیشتر ذکر شد، مقداری که از سمت کلاینت به سرور پاس داده می شود، در پارامتر eventArgument این متد قرار می گیرد.
متد GetCallbackResult پس از متد RaiseCallbackEvent اجرا می شود و وظیفه ی انتقال داده ها به کلاینت را بر عهده دارد.

*توجه مهم:*
محدودیتی که در ارتباط با استفاده از Callbacks در ASP.NET 2.0 وجود دارد این است که مقادیر ارسالی به کلاینت تنها می توانند مقادیر رشته ای باشند و "مقادیر نوع دار" قابلیت ارسال شدن ندارند. بنابرین داده ها پیش از آنکه به سمت کلاینت ارسال شوند باید به مقدار رشته ای تبدیل شوند.

بحث را با یک مثال پیش میبرم.
فرض کنید کاربر مقداری را در یک TextBox وارد می کند و شما قصد دارید پیغام مناسبی را بر مبنای مقدار وارد شده توسط وی بر روی صفحه نشان دهید.
با توجه به اطلاعات قبلی می دانید که مقدار TextBox باید در پارامتر اول تابع DoServerAction قرار بگیرد. پس نیاز به تابع جاوا اسکریپتی داریم که این کار را برای ما انجام دهد:

<input  type="text"  id="txtID" />
<input type="button" value="Submit" onclick="GetID()" />

 function GetID()
{

var valueID = document.getElementById("txtID").value;
DoServerAction(valueID,'');

}

قدم به قدم پیش می رویم.
کاربر پس از وارد کردن مقداری در TextBox بر روی دکمه کلیک می کند.
تابع جاوا اسکریپت GetID اجرا می شود. در این تابع، مقدار TextBox در متغیر valueID قرار می گیرد و این متغیر به تابع DoServerAction پاس داده می شود.
تابع DoServerAction اجرا می شود.
مقدار valueID در پارامتر eventArgument متد RaiseCallbackEvent قرار میگیرد و این متد فراخوانی می شود.
این متد وظیفه ی آماده سازی مقدار لازم برای متد GetCallbackResult را بر عهده دارد.
در متد RaiseCallbackEvent به شکل زیر عمل می کنیم:

protected  string strReturn;

public void RaiseCallbackEvent(string eventArgument)
{
if (!String.IsNullOrEmpty(eventArgument))
{
   strReturn = eventArgument;
}
}

حال متد GetCallbackResult اجرا می شود.

public  string GetCallbackResult() {

string strData = strReturn;

string tmp = String.Empty;

switch (strData) {
case "100":
   tmp = "Hello";
   break;
case "200":
   tmp = "my Name is Behrouz";
   break;
case "300":
   tmp = "barnamenevis.org";
   break;
default:
   tmp = "Try Again!";
   break;
}

return tmp;

}

مقدار برگشتی (متغیر tmp)، در تابع RecieveDataFromServer قرار می گیرد.
این تابع را به شکل زیر ایجاد می کنیم:

function RecieveDataFromServer(strData)
{
   document.getElementById("myDiv").innerHTML = strData;
}

"myDiv"، یک تگ DIV است:


<div  id="myDiv"  runat="server">

مثال فوق تنها یک مثال ساده در ارتباط با بکارگیری Callback ها در ASP.NET 2.0 بود. Callback ها می توانند با DropDownList، TreeView، GridView و بسیاری از کنترل های دیگر در دات نت استفاده شوند.

موفق باشید.

----------


## Behrouz_Rad

*توجه:
کلیه ی حقوق این مقاله متعلق به سایت www.barnamenevis.org می باشد.
استفاده از مطالب این مقاله منوط به ذکر نام منبع است.*

*فایل ضمیمه ی مقاله را از انتهای همین مقاله داونلود کنید.*

این مقاله، از مطالب مقاله ی فوق بهره می برد.
پس از آشنایی با تکنیک Client Callbacks در ASP.NET 2.0، در این مقاله قصد دارم تا به نحوه ی ثبت رکورد در بانک اطلاعاتی بدون Postback صفحه به شکلی خاص بپردازم.

*توجه مهم:*
تعدادی از دوستان در مورد تفاوت یا مزیت استفاده از این روش با ابزارها و کتابخانه هایی که بدین منظور ایجاد شده است پرسیده بودند.
باید گفت که نمیشه تفاوت خاصی رو بین این روش و ابزارهایی که به منظور تسهیل در استفاده از AJAX عرضه شدند قائل شد.
اگر تفاوتی وجود داشته باشد در جزئیات هست نه کلیات!
مثالی که در این مقاله بدان پرداخته میشه، تا حدودی این جزئیات رو مشخص می کنه.

جاوا اسکریپت، عنصر اصلی در استفاده از AJAX هست. هر چقدر که "ابزارها" و "توسعه های فراوان" نیز بدین منظور ارائه شوند، باز هم نیاز مبرم به جاوا اسکریپت برای سفارشی کردن برنامه وجود دارد.
باز هم تاکید می کنم که مثالی که در این مقاله ارائه و تحلیل میشه، استفاده از جاوا اسکریپت رو به عنوان یک عنصر اصلی در کنار خود نشان می دهد.
تا حد امکان از "اضافه نویسی" و "پیچیدگی های متداول!" پرهیز شده و مقاله و برنامه به صورت خوانا، روان و ساده ارائه شده.

صورت مسئله:
در صفحه ای به کاربر اجازه ی وارد کردن اطلاعاتی شامل: "نام"، "نام خانوادگی"، "شماره تماس" و "محل سکونت" داده می شود.
قصد بر آن است که این اطلاعات *بدون PostBack صفحه* در دیتابیس ذخیره شوند و داده های وارد شده به شکل جدول، در صفحه نمایش داده شوند.
روش خاص اضافه کردن اطلاعات که در ابتدا بدان اشاره شد آن است که تنها اطلاعاتی در جدول نمایش داده می شوند که کاربر جاری آنها را وارد کرده است. به عنوان مثال، اگر 2 کاربر در 2 مکان مختلف اقدام به وارد کردن اطلاعات کنند، هر کاربر تنها رکوردهایی را خواهد دید که خود وارد کرده است.
روشی که کاربر بتواند تمامی اطلاعات را ببیند در مقاله ای جدا بدان خواهم پرداخت.

همان طور که در مقاله ی قبل گفته شد، پیش از هر چیز نیاز داریم تا: "تابع جاوا اسکریپتی ایجاد شود که وظیفه ی ارسال درخواست به سرور و دریافت نتیجه را انجام دهد."
کد این تابع به شکل زیر ایجاد میشد:

protected  void Page_Load(object sender, EventArgs e)

{
string CR_REF = ClientScript.GetCallbackEventReference(this, "myValue", "ReceiveDataFromServer", "validateF");

if (!ClientScript.IsClientScriptBlockRegistered("DoSe  rverAction"))
{
   string SERVER_SCRIPT = @" function DoServerAction(myValue,validateF) { " + CR_REF + "}";
   ClientScript.RegisterClientScriptBlock(this.GetTyp  e(), "DoServerAction", SERVER_SCRIPT, true);
}

}



باز هم از مطالب مقاله ی قبل به یاد دارید که: "متد RaiseCallbackEvent در زمان ایجاد Callback (فراخوانی تابع DoServerAction) فراخوانی می شود و مقداری که از سمت کلاینت به سرور پاس داده می شود، در پارامتر eventArgument این متد قرار می گیرد."
پس متد RaiseCallbackEvent بهترین مکان برای اضافه کردن رکورد در دیتابیس است!
پس ابتدا نیاز به روالی داریم که وظیفه ی ثبت رکورد را برای ما انجام دهد.
در این مقاله به خاطر سهولت کار از دیتابیس Access استفاده کردم. روال مورد نیاز را به شکل زیر ایجاد می کنیم:

private string InsertRecord(string DataToInsert)
    {
        OleDbConnection Cnn = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;  Data Source=" + Server.MapPath(".") + "\\Data\\DB_Callback.mdb;");
        OleDbCommand Cmd = new OleDbCommand("INSERT INTO tbl_Callback(strName,strFamily,strPhone,strLocatio  n) VALUES(?,?,?,?)", Cnn);
        string[] arrClientValues = DataToInsert.Split("|".ToCharArray());

        Cmd.Parameters.AddWithValue("@paramName", arrClientValues[0]);
        Cmd.Parameters.AddWithValue("@paramFamily", arrClientValues[1]);
        Cmd.Parameters.AddWithValue("@paramPhone", arrClientValues[2]);
        Cmd.Parameters.AddWithValue("@paramLocation", arrClientValues[3]);

        try
        {
            Cnn.Open();
            Cmd.ExecuteNonQuery();
        }
        catch (OleDbException ex)
        {
            return "0";
        }
        catch (Exception ex)
        {
            return "0";
        }
        finally
        {
            Cnn.Close();
            if (Cmd != null) Cmd.Dispose();
        }

        return "1";

    }

تشریح عملکرد تابع فوق:
همان طور که ملاحظه می کنید، تابع فوق، مقداری از نوع رشته ای را که حاوی داده های مورد نظر برای درج در دیتابیس است به عنوان پارامتر ورودی دریافت می کند.
همچنین برای آگاهی از صحت عملکرد تابع در درج رکورد، این تابع مقدار "یک" یا "صفر" را که به ترتیب بیانگر "موفقیت" یا "عدم موفقیت" تابع در ثبت رکورد است برگشت می دهد. به این مقدار برگشتی در سمت کلاینت نیاز مبرم داریم...
نکته ای که احتمالا متوجه آن شده اید این است که ما چهار فیلد داریم اما تابع "InsertRecord" تنها یک مقدار را به عنوان پارامتر ورودی میگیرد!
دلیل این امر آن است که تکنیک Client Callbacks در ASP.NET 2.0 به ما تنها اجازه ی ارسال یک مقدار را در یک لحظه به سرور می دهد و این مقدار در پارامتر اول متد DoServerAction قرار می گیرد.
پس این مقادیر را در سمت کلاینت به هم متصل، و به منظور تشخیص هر مقدار، مقادیر را با کاراکتر "|" از یکدیگر جدا می کنیم. این مقادیر در سمت سرور (تابع InsertRecord) به وسیله ی متد "Split" از هم جدا می شوند.
توجه داشته باشید که کاراکتر "|" یک کاراکتر دلخواه است. معمولا باید کاراکتری را در نظر بگیرید که مطمئن هستید کاربر آن کاراکتر را به عنوان داده های ورودی وارد نمی کند. در غیر اینصورت برنامه در تشخیص مقادیر دچار مشکل خواهد شد.

پس از آشنایی با نحوه ی عملکرد تابع InsertRecord و پیاده سازی آن، باید آن را در مکانی مناسب فراخوانی کرد.
همان طور که پیشتر ذکر شد، متد "RaiseCallbackEvent" بهترین مکان برای این فراخوانی است!

protected string strReturn;
protected string insertResult;

public void RaiseCallbackEvent(string eventArgument)
{
   if (!String.IsNullOrEmpty(eventArgument))
   {
      strReturn = eventArgument;
      insertResult = InsertRecord(strReturn);
   }
}

مقادیر وارد شده توسط کاربر، پس از آنکه در سمت کلاینت به هم متصل و به سرور ارسال شدند، در پارامتر "eventArgument" قرار می گیرند. متغیر "strReturn" این مقدار را گرفته و به تابع "InsertRecord" پاس می دهد.
متغیر "insertResult" نیز نتیجه ی برگشتی حاصل از عملکرد تابع را در خود نگاه می دارد.

تنها کار باقیمانده، برگشت نتیجه ی کار (متغیر insertResult) به کلاینت است و همان طور که می دانید، متد "GetCallbackResult" این کار را انجام می دهد.

public string GetCallbackResult()
{
   string retResult = insertResult;
   return retResult;
}

خسته نباشید! کار ما در سمت سرور تمام شد!
حال نوبت به قسمت اصلی کار(!) در سمت کلاینت رسیده است.

ابتدا توضیحی مختصر در مورد عناصر  تشکیل دهنده ی صفحه:
سه TextBox، یک DropDownList (به منظور انتخاب محل سکونت) و یک Button.
یک المنت "DIV" با نام "Message" برای نمایش پیغام.
یک المنت "TABLE" با نام "tblResults" برای نمایش داده های وارد شده توسط کاربر. این TABLE در یک DIV قرار دارد که در ابتدا خاصیت "visibility" آن برابر با "hidden" است. پس TABLE در ابتدا نمایش داده نمی شود.



برای درک بهتر کدهای جاوا اسکریپت سمت کلاینت، به ترتیب روند اجرای کدها پیش می رویم...
کاربر پس از وارد کردن مقادیر در TextBox و انتخاب محل سکونت، بر روی دکمه کلیک می کند.
تابع جاوا اسکریپت "doAction" اجرا می شود.
بهتره نگاهی به تابع "doAction" بیندازیم.

function doAction() 
{
   document.getElementById("btnAddRecord").style.curs  or = "wait";   
   document.body.style.cursor = "wait"; 
   document.getElementById("Message").innerHTML = "...در حال ثبت اطلاعات. لطفا چند لحظه صبر کنید";
   var ref_drpLocation = document.getElementById("drpLocation");
   var selItem = ref_drpLocation.options[ref_drpLocation.selectedIndex].value;
   var sentData = "";
         sentData += document.getElementById("txtName").value;
         sentData += "|" + document.getElementById("txtFamily").value;
         sentData += "|" + document.getElementById("txtPhone").value;
         sentData += "|" + selItem;
   DoServerAction(sentData,'');
}

مطمئنا در سایت www.barnamenevis.org در هنگام ارسال پست با عبارت "نوشته شما هم اکنون در حال فرستاده شدن است ... اندکی صبر کنید" مواجه شده اید.
همچنین  اشاره گر ماوس نیز به صورت "ساعت شنی" ظاهر می شود.
در دو خط ابتدایی تابع فوق، اشاره گر ماوس در زمان قرارگیری بر روی دکمه و صفحه تغییر حالت خواهد داد. در خط سوم نیز عبارت "در حال ثبت اطلاعات. لطفا چند لحظه صبر کنید..." در المنت "DIV" قرار می گیرد.
پس از ایجاد یک ارجاء به DropDownList و به دست آوردن مقدار انتخاب شده در آن، متغیر "sentData" را با مقادیر وارد شده توسط کاربر پُر می کنیم. پیشتر ذکر شد که این مقادیر با کاراکتر "|" از یکدیگر متمایز می شوند.
در پایان، تابع "DoServerAction" را با مقادیر جمع آوری شده که در متغیر "sentData" قرار گرفتند فراخوانی می کنیم.
پس از اجرای عملیات در سمت سرور، در صورتی که روند ثبت رکورد با موفقیت انجام پذیرد، مقدار "یک" برگشت داده می شود و در پارامتر "strData" تابع جاوا اسکریپت "ReceiveDataFromServer" قرار می گیرد.
تابع "ReceiveDataFromServer" اجرا می شود.
ابن تابع، نتیجه ی پردازش را دریافت می کند و می توان بر مبنای آن عمل دلخواه را انجام داد.
نگاهی به تابع "ReceiveDataFromServer" می اندازیم...

function ReceiveDataFromServer(strData)
{
   if (strData == "1") //Record Successfully Inserted
   {
      document.getElementById("tblContainer").style.visi  bility = "visible"; 
      var ref_drpLocation = document.getElementById("drpLocation");
      var selItem = ref_drpLocation.options[ref_drpLocation.selectedIndex].value; 
      var result = "";
            result += document.getElementById("txtName").value;
            result += "|" + document.getElementById("txtFamily").value;
            result += "|" + document.getElementById("txtPhone").value;
            result += "|" + selItem;
      createElem(result);
      document.getElementById("Message").innerHTML = "";
      document.getElementById("btnAddRecord").style.curs  or = "default";   
      document.body.style.cursor = "default"; 
   }
   else
   {
      document.getElementById("Message").innerHTML = "<font color='red'>!خطا در ثبت اطلاعات</font>";
      document.getElementById("btnAddRecord").style.curs  or = "default";   
      document.body.style.cursor = "default";
   }
}

عملی که قصد انجام آن را در تابع "ReceiveDataFromServer" داریم، ایجاد و نمایش ردیف برای TABLE به ازای هر رکورد وارد شده توسط کاربر و نمایش آن بر روی صفحه است
گفته شد که: "در صورتی که روند ثبت رکورد با موفقیت انجام پذیرد، مقدار "یک" برگشت داده می شود".
گفته ی فوق را در ابتدای تابع بررسی می کنیم.
در صورت صحت عملیات (برگشت مقدار "یک")، "DIV" را نمایان می کنیم و مقادیر وارد شده توسط کاربر را همانند آنچه که در روال "doAction" انجام دادیم به دست می آوریم.
مشخص شد که هدف ما ایجاد عناصر TABLE به صورت پویا است. این کار با استفاده از جاوا اسکریپت امکان پذیر هست.
تابعی با نام "createElem" ایجاد کردم که وظیفه ی ایجاد ساختار مورد نیاز برای TABLE (ایجاد TD ها و TR ها) و انتساب آنها به TABLE را انجام می دهد...

function createElem(elemText) 
{
   var row = document.createElement("tr");
   var tmpArray = elemText.split("|");
       
   for (var i=0;i<tmpArray.length;i++)
   {
      var cell = createCell(tmpArray[i]);
      row.appendChild(cell);
   } 
        
      row.className = "trResultsItem";
      document.getElementById("tbResults").appendChild(r  ow);
      return false;
}

تابع فوق با قبول یک مقدار ورودی، این مقادیر را که همان مقادیر وارد شده توسط کاربر هستند و به وسیله ی کاراکتر "|" از یکدیگر مجزا شده اند در یک آرایه قرار می دهد. با استفاده از اندیس این آرایه می توان به مقادیر ورودی دست پیدا کرد.
در ابتدا یک المنت "TR" ایجاد می شود. سپس تابع "createCell" به تعداد مقادیر ورودی به منظور ایجاد هر سلول (TD) فراخوانی می شود.
تابع "createCell" را در ذیل مشاهده می کنید:

function createCell(text) 
{
   var cell = document.createElement("td");
   var tdText = document.createTextNode(text);
   cell.appendChild(tdText);
   return cell;
}

تابع فوق، یک المنت TD را ایجاد کرده و عبارت مورد نظر را که در پارامتر "text" قرار می گیرد به آن نسبت می دهد.
به تابع "createElem" باز می گردیم.
پس از فراخوانی تابع "createCell"، المنت TD ایجاد شده به المنت TR نسبت داده می شود.
سپس برای فرمت دهی به ردیف ایجاد شده، خاصیت "className" ردیف برابر با "trResultsItem" قرار داده شده است. خصوصیات تعریف شده برای کلاس "trResultsItem" در فایل "StyleSheet.css" برنامه قرار دارد.
توجه داشته باشید که می توان از متد "setAttribute" نیز به جای خاصیت "className" استفاده کرد اما متد "setAttribute" در Internet Explorer برای مقدار دهی به خاصیت "class" المنت کاربردی نخواهد داشت! اما خاصیت "className" در اکثر مرورگرها (همانند IE، Firefox، Opera) ساپورت می شود.

در نهایت، ردیف ایجاد شده به المنت "TBODY" ی "TABLE" نسبت داده می شود تا به عنوان یکی از ردیف های TABLE ثبت و نمایش داده شود.

*توجه مهم:*
همان طور که تا کنون متوجه شده اید، فرآیند ایجاد و نمایش پویای ردیف ها به طور کامل در سمت کلاینت انجام می شود! و این بدان معناست که نیازی به بازیابی کل اطلاعات از سرور نداریم! پُر واضح است که سرعت عملیات در این حالت به طرز چشمگیری افزایش پیدا خواهد کرد. البته توجه داشته باشید که این فرآیند مربوط به حالت خاصی از عمل ثبت است که نحوه ی انجام آن در ابتدای مقاله توضیح داده شد. مسلما در حالتی که نیاز به نمایش کلیه ی اطلاعات وارد شده توسط کاربران باشد، نیاز به بازیابی اطلاعات بیشتری از سمت سرور وجود دارد. در حالت کنونی، تنها مقدار "صفر" یا "یک" بازیابی می شود اما در حالتی که بدان اشاره شد، نیاز به بازیابی کلیه ی اطلاعات است.

حال ادامه ی تابع "ReceiveDataFromServer" را بررسی می کنیم.
پس از آنکه تابع "createElem" کار خود را با موفقیت انجام داد، پیغام نمایش داده شده در زمان ثبت رکورد در المنت "DIV" از بین می رود و اشاره گر ماوس به حالت اولیه ی خود باز می گردد.
در صورتی که روال ثبت رکورد با مشکلی مواجه شود، مقدار "صفر" برگشت داده خواهد شد. در این حالت پیغام " خطا در ثبت اطلاعات!" در المنت "DIV" نمایان می شود و اشاره گر ماوس نیز به حالت اولیه ی خود باز می گردد.

خسته نباشید! کار ما به پایان رسید.
تکنیک Client Callbacks انعطاف پذیری فوق العاده ای دارد. دست برنامه نویس را در ایجاد موقعیت های دلخواه و سفارشی باز می گذارد. البته خلق این موقعیت ها مستلزم آشنایی در حد متوسط با جاوا اسکریپت است. مسلما استفاده از این امکان جدید برای افرادی که رابطه ی خوبی با جاوا اسکریپت ندارند چندان خوشایند نیست...

در قسمت بعد، مطالب جالب تری در مورد این تکنیک خواهید خواند.
این سلسله مقالات پس از پایان به صورت نسخه ی "PDF" در دسترس قرار خواهند گرفت.

فایل ضمیمه ی مقاله از قسمت ذیل قابل دریافت است. این فایل، برنامه ی مقاله ی قبل را نیز در بر دارد.

موفق باشید.

----------


## Behrouz_Rad

*توجه:
کلیه ی حقوق این مقاله متعلق به سایت www.barnamenevis.org می باشد.
استفاده از مطالب این مقاله منوط به ذکر نام منبع است.*

*فایل ضمیمه ی مقاله را از انتهای همین مقاله داونلود کنید.*

این مقاله، از مطالب مقالات فوق بهره می برد.

در مقاله ی پیشین نحوه ی خاصی از ثبت رکورد را دیدید که در آن هر کاربر تنها می توانست رکوردهایی را مشاهده کند که خود وارد کرده است.
در این مقاله به شیوه ای پرداخته خواهد شد که تمامی رکوردها از سرور بازیابی و توسط کاربر قابل مشاهده هستند.
با توجه به توضیحات پیشین، نیاز به توضیح کمتری احساس می شود و تنها به ذکر تغییرات اکتفا می کنم.

*در سمت سرور:*
ابتدا نیاز به تابعی است که رکوردهای دلخواه را از دیتابیس استخراج و برگشت دهد.
نام این تابع را "FetchData" می گذاریم و آن را به شکل زیر ایجاد می کنیم:

protected string FetchData()
{
    string strData = String.Empty;
    OleDbConnection Cnn = new OleDbConnection("Provider=Microsoft.JET.OLEDB.4.0;  Data Source=" + Server.MapPath(".") + "\\Data\\DB_Callback.mdb;");
    OleDbCommand Cmd = new OleDbCommand("SELECT * FROM tbl_Callback", Cnn);
    OleDbDataReader DR = null;
    try
    {
        Cmd.Connection.Open();
        DR = Cmd.ExecuteReader();

        while (DR.Read())
        {
            strData += DR["strName"] + "|" + DR["strFamily"] + "|" + DR["strPhone"] + "|" + DR["strLocation"] + "~";
        }

        strData = strData.Substring(0, strData.LastIndexOf("~"));
    }
    catch (OleDbException)
    {
    }
    catch (Exception)
    {
    }
    finally
    {
        if (DR != null) DR.Close();
        Cnn.Close();
    }
    return strData;
}

تشریح تابع فوق:
داده های در یک Data Reader قرار می گیرند. با یک حلقه ی while، رکوردهای موجود در Data Reader در متغیر strData قرار می گیرند. مقدار هر فیلد با کاراکتر "|" از یکدیگر متمایز شده اند. برای شناخت هر رکورد نیز کاراکتر "~" در انتهای هر رکورد قرار می گیرد.

تابع "InsertRecord" نیز مشمول تغییر اندکی شده است.
در صورتی که این تابع کار خود را با موفقیت انجام دهد، مقدار بازگشتی به شکل زیر خواهد بود:

return "1|" + FetchData();

در سمت کلاینت، اولین مقدار برگشتی که عدد "یک" یا "صفر" است در اولین خانه ی آرایه قرار می گیرد و با بررسی این مقدار از صحت ثبت اطلاعات اطمینان حاصل می کنیم.
تابعی با نام "createTable" نیز در سمت کلاینت اضافه شده که وظیفه ی ایجاد سطرهای جدول را با استفاده از داده های دریافتی از سمت سرور بر عهده دارد.
این تابع باید در اولین مرتبه ی ورود به صفحه اجرا شود.
در ابتدای روال "Page_Load"، این تابع را جهت فراخوانی به صفحه اضافه می کنیم:

if (!ClientScript.IsStartupScriptRegistered("firstDra  w"))
{
   string dataRet = FetchData();
   string FIRST_DRAW_SCRIPT = @"createTable('" + dataRet + "');";
   ClientScript.RegisterStartupScript(this.GetType(), "firstDraw", FIRST_DRAW_SCRIPT, true);
}

نکته مهم:
همان طور که ملاحظه می کنید، از متد "RegisterStartupScript" برای اضافه کردن دستور فراخوانی تابع استفاده شده است. متد فوق، تابع یا اسکریپت مورد نظر را در انتهای صفحه قرار می دهد. در این حالت تمامی عناصر صفحه توسط اسکریپ مورد نظر قابل دسترسی هستند.
در صورتی که از متد "RegisterClientScriptBlock" استفاده کنید، چون تابع قبل از عناصر صفحه ایجاد می شود، طبیعتا به عناصر صفحه دسترسی نخواهد داشت و خطای "myElement Has No Properties" رخ خواهد داد.
"myElement" نام عنصری است که تابع قصد دسترسی به آن را دارد.

و اما تغییرات صورت گرفته در سمت کلاینت:
در تابع "ReceiveDataFromServer"، دو خط زیر اضافه شده اند:

clearTable(document.getElementById("tbResults"));
createTable(strData.substring(2, strData.length));

تابع "clearTable" به منظور حذف کلیه ی سطرهای المنت TABLE نوشته شده است:

function clearTable(tbody) 
{
   while (tbody.rows.length > 0) 
   {
      tbody.deleteRow(0);
   }
}

تابع "createTable" نیز (همان گونه که پیشتر اشاره شد)، وظیفه ی ایجاد سطرهای جدول را بر عهده دارد:

function createTable(tableText)
{
   var tmpArray = tableText.split("~");
       
   for (var i=0;i<tmpArray.length;i++)
   {
      createRow(tmpArray[i]);
   }
   document.getElementById("tblContainer").style.visi  bility = "visible";
   return false;
}

این تابع، تابع "createRow" را برای ایجاد سطر فراخوانی می کند و تابع "createRow" نیز تابع "createCell" را به منظور ایجاد هر یک از سلول های خود فراخوانی می کند.

در مقاله ی بعد، نحوه ی اضافه کردن قابلیت های "حذف" و "ویرایش" را خواهید خواند.

فایل اضافه شده به پروژه، "InsertWithCallback-2.aspx" نام دارد.

موفق باشید.

----------


## asgari2005

آخرین نسخه این پروژه نیز Release گردید تغییرات اعمال گشته عبارتند از:
1.استفاده از بانک اطلاعاتی SqlServer2005
2.امکان حذف هر رکورد با javascript و نیز ClientCallBack
3.امکان ویرایش هر رکورد با javascript و نیز ClientCallBack

امکانات که در نسخه بعدی قرار داده می شود عبارتند از:
1-Paging با استفاده از JavaScript
2-Sorting با استفاده از JavaScript

با تشکر از جناب راد بدلیل اجازه دادن ، قرار دادن ادامه مطالب

----------


## eyes_shut_number1

با سلام.با اجازه استاد راد قسمت اول رو با وی بی نوشتم! چون اوایل با ایمپلیمنت کردن و تبدیل کد به وی بی مشکل داشتم .امیدوارم این کار به درد کسی بخوره.ضمنا از مستر راد هم تشکر میکنم چون مقاله کاملی هست.سعی میکنم بقیه رو هم وی بی کنم بذارم اگه مشکلی از نظر شما نداشته باشه. فایلم از این پایین ید ال کنید

----------

