Selama beberapa minggu terakhir sejak MS Ajax Beta diluncurkan, saya mendapatkan sejumlah laporan tentang kontrol wwHoverPanel yang mengalami beberapa masalah saat dijalankan bersama dengan MS Ajax. Kontrol itu sendiri tidak mengganggu MS AJAX secara langsung, tetapi jika Anda memasukkan kontrol ke dalam AJAX UpdatePanel() ada masalah karena kode skrip yang dikeluarkan kontrol tidak dihasilkan dengan benar ke dalam pembaruan yang dihasilkan panggilan balik . Dengan hilangnya kode skrip, kontrol masih berfungsi tetapi menunjukkan beberapa perilaku yang tidak terduga. Misalnya, panel hover yang ditempatkan pada panel pembaruan akan kehilangan posisinya dalam banyak kasus dan alih-alih muncul pada posisi kursor mouse saat ini, panel tersebut akan muncul di perbatasan kontrol kontainer tempat panel tersebut berada.
Masalahnya adalah Microosft memutuskan di MS AJAX Beta untuk menggunakan mesin pembuat skrip yang benar-benar terpisah yang digerakkan melalui kontrol ScriptManager. MS Ajax ScriptManager meniru banyak metode objek ClientScript, tetapi menyediakannya sebagai metode statis (untungnya! tanpa itu kita akan benar-benar kacau).
Jadi metode seperti RegisterClientScriptBlock, ResgisterClientScriptResources – apa pun yang berhubungan dengan memasukkan kode skrip ke halaman memiliki metode statis terkait di ScriptManager. Metode ScriptManager meneruskan Kontrol sebagai parameter pertama tambahan tetapi sebaliknya meniru ClientScriptManager yang ada.
Perilaku baru ini membuat kontrol yang ada menjadi terikat – jika kode menggunakan ClientScriptManager maka UpdatePanels tidak akan dapat melihat kode skrip (jika perlu diperbarui dalam panggilan balik). Namun pada saat yang sama pengembang kontrol tidak dapat membuat asumsi bahwa MS Ajax ScriptManager benar-benar ada.
Hasil akhir dari semua ini adalah tidak mudah untuk menangani ketidakcocokan ini dan yang perlu terjadi adalah objek pembungkus perlu dibuat yang dapat memutuskan kontrol mana yang akan digunakan. Pembungkusnya perlu memutuskan apakah MS Ajax tersedia dalam aplikasi dan jika tersedia, menggunakan Reflection untuk mengakses ScriptManager untuk menulis kode skrip apa pun.
Saya tidak dapat mengambil pujian untuk ini: Eilon Lipton memposting tentang masalah ini beberapa waktu lalu dan kodenya benar-benar yang saya perlukan untuk menyelesaikannya, saya baru saja membungkusnya ke dalam objek ClientScriptProxy yang saya gunakan pada segelintir orang kontrol. Saya pada dasarnya menambahkan beberapa metode ClientScript yang saya gunakan dalam aplikasi saya. Inilah kelasnya:
[*** kode diperbarui: 12/12/2006 dari komentar *** ]
///
/// Ini adalah objek proxy untuk
objek Page.ClientScript dan MS Ajax ScriptManager /// yang dapat beroperasi ketika MS Ajax tidak ada. Karena MS Ajax
/// mungkin tidak tersedia, mengakses metode secara langsung tidak mungkin
/// dan kita diharuskan untuk secara tidak langsung mereferensikan metode skrip klien melalui
/// kelas ini.
///
/// Kelas ini harus dipanggil saat Kontrol dimulai dan digunakan
/// untuk menggantikan semua panggilan Page.ClientScript. Panggilan Scriptmanager dilakukan
/// melalui Refleksi
///
public class ClientScriptProxy
{
private static Type scriptManagerType = null;
// *** Daftarkan metode proksi dari
MethodInfo statis pribadi ScriptManager RegisterClientScriptBlockMethod;
MethodInfo statis pribadi RegisterStartupScriptMethod;
MethodInfo statis pribadi RegisterClientScriptIncludeMethod;
MethodInfo statis pribadi RegisterClientScriptResourceMethod;
//MetodeInfo statis pribadi RegisterPostBackControlMethod;
//MethodInfo statis pribadi GetWebResourceUrlMethod;
ClientScriptManager skrip klien;
///
/// Menentukan apakah MsAjax tersedia di aplikasi Web ini
///
public bool IsMsAjax
{
get
{
if (scriptManagerType == null)
CheckForMsAjax();
kembalikan _IsMsAjax;
}
}
bool statis pribadi _IsMsAjax = false;
public bool IsMsAjaxOnPage
{
dapatkan
{
return _IsMsAjaxOnPage;
}
}
bool pribadi _IsMsAjaxOnPage = false;
///
/// Contoh terkini dari kelas ini yang harus selalu digunakan untuk
/// mengakses objek ini. Tidak ada konstruktor publik yang
/// memastikan referensi digunakan sebagai Singleton.
///
public static ClientScriptProxy Saat Ini
{
dapatkan
{
kembali
( HttpContext.Current.Items["__ClientScriptProxy"] ??
(HttpContext.Current.Items["__ClientScriptProxy"] =
ClientScriptProxy baru(HttpContext.Current.Handler sebagai Halaman )))
sebagai ClientScriptProxy;
}
}
///
/// Konstruktor dasar. Masukkan nama halaman agar kita dapat mengambil
/// stok
///
///
protected ClientScriptProxy(Page CurrentPage)
{
this.clientScript = CurrentPage .Skrip Klien;
}
///
/// Memeriksa apakah MS Ajax terdaftar dengan
aplikasi Web /// saat ini.
///
/// Catatan: Metode bersifat statis sehingga dapat diakses langsung dari
/// di mana saja
///
///
public static bool CheckForMsAjax()
{
scriptManagerType = Type. GetType("Microsoft.Web.UI.ScriptManager, Microsoft.Web.Extensions, Versi=1.0.61025.0, Budaya=netral, PublicKeyToken=31bf3856ad364e35", false);
jika (scriptManagerType != null)
{
_IsMsAjax = benar;
kembali benar;
}
_IsMsAjax = salah;
kembali salah;
}
///
/// Mendaftarkan blok skrip klien di halaman.
///
///
///
/// param>
///
///
public void RegisterClientScriptBlock(Kontrol kontrol, Tipe tipe, kunci string, skrip string, bool addScriptTags )
{
jika (ini.IsMsAjax)
{
jika (RegisterClientScriptBlockMethod == null)
RegisterClientScriptBlockMethod = scriptManagerType.GetMethod("RegisterClientScriptBlock");
RegisterClientScriptBlockMethod.Invoke(null, objek baru[5] { kontrol, tipe, kunci, skrip, addScriptTags });
}
else
this.clientScript.RegisterClientScriptBlock(tipe, kunci, skrip, addScriptTags);
}
///
/// Mendaftarkan cuplikan kode startup yang ditempatkan di bagian bawah halaman
///
///
///
///
///
///
public void RegisterStartupScript(Kontrol kontrol, Tipe tipe, kunci string, skrip string, bool addStartupTags)
{
if (this.IsMsAjax)
{
if (RegisterStartupScriptMethod == null)
RegisterStartupScriptMethod = scriptManagerType.GetMethod("RegisterStartupScript");
RegisterStartupScriptMethod.Invoke(null, objek baru[5] { kontrol, tipe, kunci, skrip, addStartupTags });
}
else
this.clientScript.RegisterStartupScript(tipe, kunci, skrip, addStartupTags);
}
///
/// Mendaftarkan tag penyertaan skrip ke dalam halaman untuk url skrip eksternal
///
///
///
///
///
public void RegisterClientScriptInclude(Kontrol kontrol, Tipe tipe, string kunci, string url)
{
if (this.IsMsAjax)
{
if (RegisterClientScriptIncludeMethod == null)
RegisterClientScriptIncludeMethod = scriptManagerType.GetMethod("RegisterClientScriptInclude");
RegisterClientScriptIncludeMethod.Invoke(null, objek baru[4] { kontrol, tipe, kunci, url });
}
lain
ini.clientScript.RegisterClientScriptInclude( tipe, kunci, url);
}
///
/// Menambahkan tag penyertaan skrip ke halaman untuk WebResource.
///
///
///
/// param>
public void RegisterClientScriptResource(Kontrol kontrol, Tipe tipe, string resourceName)
{
if (this.IsMsAjax)
{
if (RegisterClientScriptResourceMethod == null)
RegisterClientScriptResourceMethod = scriptManagerType.GetMethod("RegisterClientScriptResource");
RegisterClientScriptResourceMethod.Invoke(null, objek baru[3] { kontrol, tipe, resourceName });
}
lain
ini.clientScript.RegisterClientScriptResource(type,resourceName);
}
string publik GetWebResourceUrl(Kontrol kontrol, Tipe tipe, string resourceName)
{
//if (this.IsMsAjax)
//{
// if (GetWebResourceUrlMethod == null)
// GetWebResourceUrlMethod = scriptManagerType.GetMethod("GetScriptResourceUrl");
// mengembalikan GetWebResourceUrlMethod.Invoke(null, objek baru[2] { resourceName, control.GetType().Assembly }) sebagai string;
//}
//lainnya
kembalikan this.clientScript.GetWebResourceUrl(type, resourceName);
}
}
Kode pada dasarnya memeriksa untuk melihat apakah rakitan MS Ajax dapat diakses sebagai suatu tipe dan jika demikian, diasumsikan MS Ajax telah diinstal. Ini kurang optimal – akan lebih baik untuk mengetahui apakah ScriptManager benar-benar digunakan pada halaman saat ini, namun tanpa memindai seluruh kontrol (lambat) saya tidak dapat melihat cara melakukannya dengan mudah.
Kontrol menyimpan cache setiap struktur MethodInfo untuk menunda beberapa overhead dalam membuat panggilan Refleksi ke metode ScriptManager. Saya tidak berpikir bahwa Refleksi di sini akan menimbulkan banyak kekhawatiran tentang overhead kecuali Anda memiliki BANYAK panggilan ke metode ini (saya kira itu mungkin terjadi jika Anda memiliki banyak sumber daya – pikirkan kontrol seperti FreeTextBox misalnya). Meski begitu, overhead Refleksi mungkin tidak perlu dikhawatirkan.
Untuk menggunakan kelas ini, semua panggilan ke ClientScript diganti dengan panggilan kelas ini. Jadi di suatu tempat selama inisialisasi kontrol saya menambahkan:
protected override void OnInit(EventArgs e)
{
this.ClientScriptProxy = ClientScriptProxy.Current;
base.OnInit(e);
}
Dan kemudian untuk menggunakannya:
this.ClientScriptProxy.RegisterClientScriptInclude(ini,ini.GetType(),
ControlResources.SCRIPTLIBRARY_SCRIPT_RESOURCE,
ini.ResolveUrl(ini.ScriptLocation));
Perhatikan parameter pertama adalah instance kontrol (biasanya ini) sama seperti panggilan ScriptManager, jadi akan ada sedikit perubahan parameter saat beralih dari kode ClientScript.
Setelah saya menambahkan kode ini ke kontrol saya, masalah dengan UpdatePanel hilang dan mulai merender dengan baik lagi bahkan dengan kontrol yang dihosting di dalam UpdatePanels.