Bagikan melalui


Memperbarui dan Menghapus Data Biner (VB) yang Ada

oleh Scott Mitchell

Unduh PDF

Dalam tutorial sebelumnya kita melihat bagaimana kontrol GridView memudahkan untuk mengedit dan menghapus data teks. Dalam tutorial ini kita melihat bagaimana kontrol GridView juga memungkinkan untuk mengedit dan menghapus data biner, apakah data biner disimpan dalam database atau disimpan dalam sistem file.

Pendahuluan

Selama tiga tutorial terakhir, kami telah menambahkan sedikit fungsionalitas untuk bekerja dengan data biner. Kami mulai dengan menambahkan BrochurePath kolom ke Categories tabel dan memperbarui arsitektur yang sesuai. Kami juga menambahkan metode Lapisan Akses Data dan Lapisan Logika Bisnis untuk bekerja dengan kolom tabel Kategori yang ada Picture , yang menyimpan konten biner dari file gambar. Kami telah membuat halaman web untuk menyajikan data biner di GridView dan menyediakan tautan unduhan untuk brosur, dengan gambar kategori ditampilkan dalam elemen <img>. Kami juga telah menambahkan DetailsView untuk memungkinkan pengguna menambahkan kategori baru serta mengunggah data brosur dan gambar kategori tersebut.

Yang tersisa untuk diimplementasikan adalah kemampuan untuk mengedit dan menghapus kategori yang ada, yang akan kita capai dalam tutorial ini menggunakan fitur pengeditan dan penghapusan bawaan GridView. Saat mengedit kategori, pengguna akan dapat secara opsional mengunggah gambar baru atau memiliki kategori terus menggunakan yang sudah ada. Untuk brosur, mereka dapat memilih untuk menggunakan brosur yang ada, untuk mengunggah brosur baru, atau untuk menunjukkan bahwa kategori tidak lagi memiliki brosur yang terkait dengannya. Mari kita mulai!

Langkah 1: Memperbarui Lapisan Akses Data

DAL memiliki metode Insert, Update, dan Delete yang dihasilkan secara otomatis, tetapi metode ini dihasilkan berdasarkan kueri utama CategoriesTableAdapter, yang tidak menyertakan kolom Picture. Oleh karena itu, metode Insert dan Update tidak menyertakan parameter untuk menentukan data biner gambar kategori. Seperti yang kami lakukan dalam tutorial sebelumnya, kita perlu membuat metode TableAdapter baru untuk memperbarui Categories tabel saat menentukan data biner.

Buka Typed DataSet dan, dari Perancang, klik kanan pada CategoriesTableAdapter s header dan pilih Tambah Kueri dari menu konteks untuk meluncurkan Konfigurasi Kueri TableAdapter. Panduan ini dimulai dengan menanyakan kepada kami bagaimana kueri TableAdapter harus mengakses database. Pilih Gunakan pernyataan SQL dan klik Berikutnya. Langkah berikutnya meminta jenis kueri yang akan dibuat. Karena kita membuat kueri untuk menambahkan rekaman baru ke Categories tabel, pilih PERBARUI dan klik Berikutnya.

Pilih Opsi PERBARUI

Gambar 1: Pilih Opsi PERBARUI (Klik untuk melihat gambar ukuran penuh)

Kita sekarang perlu menentukan UPDATE pernyataan SQL. Wizard secara otomatis menyarankan pernyataan UPDATE yang sesuai dengan kueri utama TableAdapter (yang memperbarui nilai CategoryName, Description, dan BrochurePath). Ubah pernyataan sehingga Picture kolom disertakan bersama dengan @Picture parameter, seperti:

UPDATE [Categories] SET 
    [CategoryName] = @CategoryName, 
    [Description] = @Description, 
    [BrochurePath] = @BrochurePath ,
    [Picture] = @Picture
WHERE (([CategoryID] = @Original_CategoryID))

Layar akhir asisten meminta kita untuk memberi nama metode TableAdapter baru. Masukkan UpdateWithPicture dan klik Selesai.

Beri nama Metode TableAdapter Baru UpdateWithPicture

Gambar 2: Beri nama Metode UpdateWithPicture TableAdapter Baru (Klik untuk melihat gambar ukuran penuh)

Langkah 2: Menambahkan Metode Lapisan Logika Bisnis

Selain memperbarui DAL, kita perlu memperbarui BLL untuk menyertakan metode untuk memperbarui dan menghapus kategori. Ini adalah metode yang akan dipanggil dari Lapisan Presentasi.

Untuk menghapus kategori, kita dapat menggunakan metode yang dihasilkan secara otomatis CategoriesTableAdapterDelete. Tambahkan metode berikut ke CategoriesBLL kelas :

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteCategory(ByVal categoryID As Integer) As Boolean
    Dim rowsAffected As Integer = Adapter.Delete(categoryID)
    ' Return true if precisely one row was deleted, otherwise false
    Return rowsAffected = 1
End Function

Untuk tutorial ini, mari kita buat dua metode untuk memperbarui kategori - satu yang menerima data gambar biner dan memanggil metode UpdateWithPicture yang baru saja kita tambahkan ke CategoriesTableAdapter dan yang lain yang hanya menerima nilai CategoryName, Description, dan BrochurePath dan menggunakan pernyataan yang dihasilkan secara otomatis CategoriesTableAdapter dari kelas Update. Alasan di balik penggunaan dua metode adalah bahwa dalam beberapa keadaan, pengguna mungkin ingin memperbarui gambar kategori bersama dengan bidang lainnya, dalam hal ini pengguna harus mengunggah gambar baru. Data biner gambar yang diunggah kemudian dapat digunakan dalam UPDATE pernyataan. Dalam kasus lain, pengguna mungkin hanya tertarik untuk memperbarui, misalnya, nama dan deskripsi. Tetapi jika UPDATE pernyataan mengharapkan data biner untuk Picture kolom juga, maka kita juga perlu memberikan informasi tersebut. Ini akan memerlukan perjalanan tambahan ke database untuk membawa kembali data gambar untuk rekaman yang sedang diedit. Oleh karena itu, kita menginginkan dua UPDATE metode. Lapisan Logika Bisnis akan menentukan mana yang akan digunakan berdasarkan apakah data gambar disediakan saat memperbarui kategori.

Untuk memfasilitasi hal ini, tambahkan dua metode ke CategoriesBLL kelas , keduanya bernama UpdateCategory. Yang pertama harus menerima tiga String s, Byte array, dan Integer sebagai parameter inputnya; yang kedua, hanya tiga String s dan Integer. Parameter String input digunakan untuk nama kategori, deskripsi, dan jalur file brosur, array Byte digunakan untuk isi biner dari gambar kategori, dan Integer digunakan untuk mengidentifikasi CategoryID dari catatan yang akan diperbarui. Perhatikan bahwa kelebihan beban pertama memanggil yang kedua jika array yang diteruskan Byte adalah Nothing:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, False)> _
Public Function UpdateCategory(categoryName As String, description As String, _
    brochurePath As String, picture() As Byte, categoryID As Integer) As Boolean
    
    ' If no picture is specified, use other overload
    If picture Is Nothing Then
        Return UpdateCategory(categoryName, description, brochurePath, categoryID)
    End If
    ' Update picture, as well
    Dim rowsAffected As Integer = Adapter.UpdateWithPicture _
        (categoryName, description, brochurePath, picture, categoryID)
    ' Return true if precisely one row was updated, otherwise false
    Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateCategory(categoryName As String, description As String, _
    brochurePath As String, categoryID As Integer) As Boolean
    Dim rowsAffected As Integer = Adapter.Update _
        (categoryName, description, brochurePath, categoryID)
    ' Return true if precisely one row was updated, otherwise false
    Return rowsAffected = 1
End Function

Langkah 3: Menyalin Di Atas Fungsionalitas Sisipkan dan Lihat

Dalam tutorial sebelumnya , kami membuat halaman bernama UploadInDetailsView.aspx yang mencantumkan semua kategori dalam GridView dan menyediakan DetailsView untuk menambahkan kategori baru ke sistem. Dalam tutorial ini kita akan memperluas GridView untuk menyertakan pengeditan dan penghapusan dukungan. Daripada terus bekerja dari UploadInDetailsView.aspx, mari kita menempatkan perubahan tutorial ini di UpdatingAndDeleting.aspx halaman dari folder yang sama, ~/BinaryData. Salin dan tempel markup dan kode deklaratif dari UploadInDetailsView.aspx ke UpdatingAndDeleting.aspx.

Mulailah dengan membuka UploadInDetailsView.aspx halaman. Salin semua sintaks deklaratif dalam elemen <asp:Content>, seperti yang ditunjukkan pada Gambar 3. Selanjutnya, buka UpdatingAndDeleting.aspx dan tempel markup ini dalam elemennya <asp:Content> . Demikian pula, salin kode dari class code-behind halaman UploadInDetailsView.aspx ke UpdatingAndDeleting.aspx.

Salin Markup Deklaratif dari UploadInDetailsView.aspx

Gambar 3: Salin Markup Deklaratif dari UploadInDetailsView.aspx (Klik untuk melihat gambar ukuran penuh)

Setelah menyalin markup dan kode deklaratif, kunjungi UpdatingAndDeleting.aspx. Anda akan melihat output yang sama dan memiliki pengalaman pengguna yang sama seperti UploadInDetailsView.aspx halaman dari tutorial sebelumnya.

Langkah 4: Menambahkan Dukungan untuk Penambahan dan Penghapusan ke ObjectDataSource dan GridView

Seperti yang kita bahas kembali dalam tutorial Gambaran Umum Menyisipkan, Memperbarui, dan Menghapus Data, GridView menyediakan kemampuan penghapusan bawaan dan kemampuan ini dapat diaktifkan dengan mencentang kotak jika sumber data dasar mendukung penghapusan. Saat ini, ObjectDataSource yang terkait dengan GridView (CategoriesDataSource) tidak mendukung penghapusan.

Untuk memperbaikinya, klik opsi Konfigurasi Sumber Data dari tag pintar ObjectDataSource untuk meluncurkan wizard. Layar pertama menunjukkan bahwa ObjectDataSource dikonfigurasi untuk bekerja dengan CategoriesBLL kelas . Tekan Berikutnya. Saat ini, hanya properti InsertMethod dan SelectMethod ObjectDataSource yang ditentukan. Namun, wizard mengisi daftar drop-down secara otomatis di tab PERBARUI dan HAPUS dengan menggunakan metode-metode UpdateCategory dan DeleteCategory. Ini karena di CategoriesBLL kelas kami menandai metode ini menggunakan DataObjectMethodAttribute sebagai metode default untuk memperbarui dan menghapus.

Untuk saat ini, atur daftar drop-down tab Perbarui ke (Tidak Ada), tetapi biarkan daftar drop-down tab Hapus diatur ke DeleteCategory. Kami akan kembali ke wizard ini di Langkah 6 untuk menambahkan dukungan pembaruan.

Mengonfigurasi ObjectDataSource untuk Menggunakan Metode DeleteCategory

Gambar 4: Konfigurasikan ObjectDataSource untuk Menggunakan DeleteCategory Metode (Klik untuk melihat gambar ukuran penuh)

Nota

Setelah menyelesaikan wizard, Visual Studio mungkin bertanya apakah Anda ingin Memperbarui Bidang dan Kunci, yang akan meregenerasi bidang kontrol Web pada data. Pilih Tidak, karena memilih Ya akan menimpa kustomisasi bidang apa pun yang mungkin telah Anda buat.

ObjectDataSource sekarang akan menyertakan nilai untuk propertinya DeleteMethod serta DeleteParameter. Ingat bahwa saat menggunakan wizard untuk menentukan metode, Visual Studio mengatur properti ObjectDataSource s OldValuesParameterFormatString ke original_{0}, yang menyebabkan masalah dengan pemanggilan metode pembaruan dan penghapusan. Oleh karena itu, hapus properti ini sama sekali atau atur ulang ke default, {0}. Jika Anda perlu me-refresh memori Anda pada properti ObjectDataSource ini, lihat tutorial Gambaran Umum Menyisipkan, Memperbarui, dan Menghapus Data .

Setelah menyelesaikan wizard dan memperbaiki OldValuesParameterFormatStringmarkup deklaratif ObjectDataSource akan terlihat mirip seperti berikut ini:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture" 
    DeleteMethod="DeleteCategory">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
    <DeleteParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Setelah mengonfigurasi ObjectDataSource, tambahkan kemampuan penghapusan ke GridView dengan mencentang kotak centang Aktifkan Penghapusan dari tag pintar GridView. Ini akan menambahkan CommandField ke GridView yang propertinya ShowDeleteButton diatur ke True.

Mengaktifkan Dukungan untuk Menghapus di GridView

Gambar 5: Aktifkan Dukungan untuk Menghapus di GridView (Klik untuk melihat gambar ukuran penuh)

Luangkan waktu sejenak untuk menguji fungsionalitas penghapusan. Ada kunci asing antara tabel ProductsCategoryID dan tabel CategoriesCategoryID, sehingga Anda akan mendapatkan pengecualian pelanggaran batasan kunci asing jika Anda mencoba menghapus salah satu dari delapan kategori pertama. Untuk menguji fungsionalitas ini, tambahkan kategori baru, yang menyediakan brosur dan gambar. Kategori pengujian saya, yang ditunjukkan pada Gambar 6, menyertakan file brosur pengujian bernama Test.pdf dan gambar pengujian. Gambar 7 menunjukkan GridView setelah kategori pengujian ditambahkan.

Menambahkan Kategori Pengujian dengan Brosur dan Gambar

Gambar 6: Tambahkan Kategori Pengujian dengan Brosur dan Gambar (Klik untuk melihat gambar ukuran penuh)

Setelah Menyisipkan Kategori Pengujian, Itu Ditampilkan di GridView

Gambar 7: Setelah Memasukkan Kategori Pengujian, Itu Ditampilkan di GridView (Klik untuk melihat gambar ukuran penuh)

Di Visual Studio, perbarui Penjelajah Solusi. Sekarang Anda akan melihat file baru di ~/Brochures folder , Test.pdf (lihat Gambar 8).

Selanjutnya, klik tautan Hapus di baris Kategori Pengujian, yang menyebabkan halaman melakukan pemuatan ulang dan metode kelas CategoriesBLL dipanggil DeleteCategory. Ini akan memanggil metode DAL s Delete , menyebabkan pernyataan yang sesuai DELETE dikirim ke database. Data kemudian di-rebound ke GridView dan markup dikirim kembali ke klien dengan Kategori Pengujian tidak ada lagi.

Meskipun alur kerja penghapusan berhasil menghapus rekaman Kategori Uji dari Categories tabel, alur kerja tersebut tidak menghapus file brosurnya dari sistem file server web. Refresh Penjelajah Solusi dan Anda akan melihat bahwa Test.pdf masih duduk di ~/Brochures folder.

File Test.pdf Tidak Dihapus dari Sistem File Server Web

Gambar 8: Test.pdf File Tidak Dihapus dari Sistem File Server Web

Langkah 5: Menghapus File Brosur dari Kategori yang Dihapus

Salah satu kelemahan penyimpanan data biner di luar database adalah bahwa langkah tambahan harus diambil untuk membersihkan file-file ini ketika rekaman database terkait dihapus. GridView dan ObjectDataSource menyediakan event yang dijalankan baik sebelum maupun sesudah perintah hapus dilakukan. Kita sebenarnya perlu membuat penanganan aktivitas untuk peristiwa pra-dan pasca-tindakan. Categories Sebelum rekaman dihapus, kita perlu menentukan jalur file PDF-nya, tetapi kita tidak ingin menghapus PDF sebelum kategori dihapus jika ada beberapa pengecualian dan kategori tidak dihapus.

Peristiwa RowDeleting GridView dilaksanakan sebelum perintah hapus ObjectDataSource dipanggil, sedangkan peristiwa RowDeleted dilaksanakan setelahnya. Buat penanganan aktivitas untuk dua peristiwa ini menggunakan kode berikut:

' A page variable to "remember" the deleted category's BrochurePath value
Private deletedCategorysPdfPath As String = Nothing
Protected Sub Categories_RowDeleting(sender As Object, e As GridViewDeleteEventArgs) _
    Handles Categories.RowDeleting
    
    ' Determine the PDF path for the category being deleted...
    Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
    Dim categoryAPI As New CategoriesBLL()
    Dim categoriesData As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categoriesData(0)
    If category.IsBrochurePathNull() Then
        deletedCategorysPdfPath = Nothing
    Else
        deletedCategorysPdfPath = category.BrochurePath
    End If
End Sub
Protected Sub Categories_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
    Handles Categories.RowDeleted
    
    ' Delete the brochure file if there were no problems deleting the record
    If e.Exception Is Nothing Then
        DeleteRememberedBrochurePath()
    End If
End Sub

Di penanganan kejadian RowDeleting, CategoryID dari baris yang sedang dihapus diambil dari koleksi DataKeys GridView, yang bisa diakses melalui koleksi e.Keys di dalam penanganan kejadian ini. Selanjutnya, kelas CategoriesBLLGetCategoryByCategoryID(categoryID) dipanggil untuk mengembalikan informasi tentang rekaman yang dihapus. Jika objek yang dikembalikan CategoriesDataRow memiliki nilai bukan-NULL``BrochurePath, maka disimpan dalam variabel halaman deletedCategorysPdfPath sehingga file dapat dihapus di pengelola acara RowDeleted.

Nota

Sebagai alternatif dari mengambil BrochurePath detail untuk rekaman dihapus dalam penanganan kejadian Categories, kita dapat menambah RowDeleting ke properti BrochurePath dalam GridView dan akses nilai rekaman melalui koleksi DataKeyNames. Melakukannya akan sedikit meningkatkan ukuran status tampilan GridView, tetapi akan mengurangi jumlah kode yang diperlukan dan menyimpan perjalanan ke database.

Setelah perintah hapus dasar dari ObjectDataSource dipanggil, penanganan peristiwa GridView RowDeleted diaktifkan. Jika tidak ada pengecualian dalam menghapus data dan ada nilai untuk deletedCategorysPdfPath, maka PDF dihapus dari sistem file. Perhatikan bahwa kode tambahan ini tidak diperlukan untuk membersihkan data biner kategori yang terkait dengan gambarnya. Itu karena data gambar disimpan langsung dalam database, jadi menghapus Categories baris juga menghapus data gambar kategori tersebut.

Setelah menambahkan dua penanganan aktivitas, jalankan kasus pengujian ini lagi. Saat menghapus kategori, PDF terkait juga dihapus.

Memperbarui data biner terkait rekaman yang ada memberikan beberapa tantangan menarik. Sisa tutorial ini membahas penambahan fungsi pembaruan pada brosur dan gambar. Langkah 6 mengeksplorasi teknik untuk memperbarui informasi brosur sementara Langkah 7 melihat pembaruan gambar.

Langkah 6: Memperbarui Brosur Kategori

Seperti yang dibahas dalam tutorial Gambaran Umum Memasukkan, Memperbarui, dan Menghapus Data, GridView menawarkan dukungan pengeditan tingkat baris bawaan yang dapat diterapkan dengan mencentang kotak centang jika sumber data yang mendasarinya dikonfigurasi dengan benar. Saat ini, CategoriesDataSource ObjectDataSource belum dikonfigurasi untuk menyertakan pembaruan dukungan, jadi mari kita tambahkan itu.

Klik tautan Konfigurasi Sumber Data dari wizard ObjectDataSource dan lanjutkan ke langkah kedua. Karena DataObjectMethodAttribute digunakan dalam CategoriesBLL, daftar drop-down UPDATE harus secara otomatis diisi dengan overload UpdateCategory yang menerima empat parameter input (untuk semua kolom kecuali Picture). Ubah ini sehingga menggunakan kelebihan beban dengan lima parameter.

Mengonfigurasi ObjectDataSource untuk Menggunakan Metode UpdateCategory yang Menyertakan Parameter untuk Gambar

Gambar 9: Konfigurasikan ObjectDataSource untuk Menggunakan UpdateCategory Metode yang Menyertakan Parameter untuk Picture (Klik untuk melihat gambar ukuran penuh)

ObjectDataSource sekarang akan menyertakan nilai untuk propertinya UpdateMethod serta nilai-nilai yang sesuai pada UpdateParameter. Seperti yang disebutkan di Langkah 4, Visual Studio mengatur properti OldValuesParameterFormatString ObjectDataSource ke original_{0} saat menggunakan wizard Konfigurasi Sumber Data. Ini akan menyebabkan masalah dengan pemanggilan metode 'update' dan 'delete'. Oleh karena itu, hapus properti ini sama sekali atau atur ulang ke default, {0}.

Setelah menyelesaikan wizard dan memperbaiki OldValuesParameterFormatStringmarkup deklaratif ObjectDataSource akan terlihat seperti berikut ini:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture" 
    DeleteMethod="DeleteCategory" UpdateMethod="UpdateCategory">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
    <DeleteParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
        <asp:Parameter Name="categoryID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Untuk mengaktifkan fitur pengeditan bawaan GridView, centang opsi Aktifkan Pengeditan dari tag pintar GridView. Ini akan mengatur properti ShowEditButtonCommandField ke True , menghasilkan penambahan tombol Edit (dan tombol Perbarui dan Batalkan untuk baris yang sedang diedit).

Mengonfigurasi GridView untuk Mendukung Pengeditan

Gambar 10: Mengonfigurasi GridView untuk Mendukung Pengeditan (Klik untuk melihat gambar ukuran penuh)

Kunjungi halaman melalui browser dan klik salah satu tombol Edit baris. CategoryName dan Description BoundFields ditampilkan sebagai kotak teks. BrochurePath TemplateField kekurangan EditItemTemplate, sehingga tetap menampilkan ItemTemplate sebagai tautan ke brosur. Picture ImageField ditampilkan sebagai TextBox yang properti Text-nya diberi nilai dari nilai DataImageUrlField milik ImageField, dalam hal ini menjadi CategoryID.

GridView Tidak Memiliki Antarmuka Pengeditan untuk BrochurePath

Gambar 11: GridView Tidak Memiliki Antarmuka Pengeditan untuk BrochurePath (Klik untuk melihat gambar ukuran penuh)

Menyesuaikan Antarmuka Pengeditan

Kita perlu membuat antarmuka pengeditan untuk BrochurePath TemplateField, yang memungkinkan pengguna untuk:

  • Tinggalkan brosur kategori as-is.
  • Perbarui brosur kategori dengan mengunggah brosur baru, atau
  • Hapus brosur kategori sama sekali (jika kategori tidak lagi memiliki brosur terkait).

Kita juga perlu memperbarui Picture antarmuka pengeditan ImageField, tetapi kita akan sampai ke ini di Langkah 7.

Dari tag pintar GridView, klik tautan Edit Templat dan pilih BrochurePath TemplateFields EditItemTemplate dari daftar drop-down. Tambahkan kontrol Web RadioButtonList ke templat ini, atur propertinya ID ke BrochureOptions dan propertinya AutoPostBack ke True. Dari jendela Properti, klik tiga titik di properti Items, yang akan membuka Editor Koleksi ListItem. Tambahkan tiga opsi berikut dengan Value s 1, 2 dan 3, masing-masing:

  • Gunakan brosur saat ini
  • Hapus brosur saat ini
  • Unggah brosur baru

Atur properti ListItem s pertama Selected ke True.

Tambahkan Tiga ListItems ke dalam RadioButtonList

Gambar 12: Tambahkan Tiga ListItem ke RadioButtonList

Di bawah RadioButtonList, tambahkan kontrol FileUpload bernama BrochureUpload. Atur properti Visible ke False.

Menambahkan RadioButtonList dan FileUpload Control ke EditItemTemplate

Gambar 13: Tambahkan RadioButtonList dan FileUpload Control ke EditItemTemplate (Klik untuk melihat gambar ukuran penuh)

RadioButtonList ini menyediakan tiga opsi untuk pengguna. Idenya adalah bahwa kontrol FileUpload akan ditampilkan hanya jika opsi terakhir, Unggah brosur baru, dipilih. Untuk mencapai hal ini, buat penangan acara untuk acara RadioButtonList SelectedIndexChanged dan tambahkan kode berikut:

Protected Sub BrochureOptions_SelectedIndexChanged _
    (sender As Object, e As EventArgs)
    
    ' Get a reference to the RadioButtonList and its Parent
    Dim BrochureOptions As RadioButtonList = _
        CType(sender, RadioButtonList)
    Dim parent As Control = BrochureOptions.Parent
    ' Now use FindControl("controlID") to get a reference of the 
    ' FileUpload control
    Dim BrochureUpload As FileUpload = _
        CType(parent.FindControl("BrochureUpload"), FileUpload)
    ' Only show BrochureUpload if SelectedValue = "3"
    BrochureUpload.Visible = (BrochureOptions.SelectedValue = "3")
End Sub

Karena kontrol RadioButtonList dan FileUpload berada dalam templat, kita harus menulis sedikit kode untuk mengakses kontrol ini secara terprogram. Penangan peristiwa SelectedIndexChanged diberikan referensi RadioButtonList sebagai parameter input sender. Untuk mendapatkan kontrol FileUpload, kita perlu mendapatkan kontrol induk RadioButtonList dan dari sana menggunakan metode FindControl("controlID"). Setelah kita memiliki referensi ke kontrol RadioButtonList dan FileUpload, properti kontrol FileUpload diatur Visible ke True hanya jika RadioButtonList SelectedValue sama dengan 3, yang merupakan Value untuk mengunggah brosur baru ListItem.

Dengan kode ini di tempat, luangkan waktu sejenak untuk menguji antarmuka pengeditan. Klik tombol Edit untuk baris. Awalnya, opsi Gunakan brosur saat ini harus dipilih. Mengubah indeks yang dipilih menyebabkan pengiriman ulang data ke server (postback). Jika opsi ketiga dipilih, kontrol FileUpload ditampilkan, jika tidak, maka akan disembunyikan. Gambar 14 menunjukkan antarmuka pengeditan saat tombol Edit pertama kali diklik; Gambar 15 memperlihatkan antarmuka setelah opsi Unggah brosur baru dipilih.

Awalnya, Opsi Gunakan brosur saat ini dipilih

Gambar 14: Awalnya, Opsi Gunakan brosur saat ini dipilih (Klik untuk melihat gambar ukuran penuh)

Memilih Opsi Unggah brosur baru Menampilkan Kontrol FileUpload

Gambar 15: Memilih Opsi Unggah brosur baru Menampilkan Kontrol FileUpload (Klik untuk melihat gambar ukuran penuh)

Menyimpan File Brosur dan MemperbaruiBrochurePathKolom

Saat tombol Perbarui GridView diklik, peristiwanya RowUpdating akan diaktifkan. Perintah pembaruan ObjectDataSource dipanggil dan kemudian peristiwa GridView RowUpdated dijalankan. Seperti alur kerja penghapusan, kita perlu membuat penanganan aktivitas untuk kedua peristiwa ini. Dalam penanganan RowUpdating aktivitas, kita perlu menentukan tindakan apa yang harus diambil berdasarkan SelectedValueBrochureOptions RadioButtonList:

  • Jika SelectedValue adalah 1, kita ingin tetap menggunakan pengaturan yang sama pada BrochurePath. Oleh karena itu, kita perlu mengatur parameter ObjectDataSource ke brochurePath nilai rekaman yang ada BrochurePath yang sedang diperbarui. Parameter dari ObjectDataSource dapat diatur menggunakan brochurePath.
  • Jika SelectedValue adalah 2, maka kita ingin mengatur nilai BrochurePath rekaman menjadi NULL. Ini dapat dicapai dengan mengatur parameter ObjectDataSource menjadi brochurePath, yang menghasilkan penggunaan database Nothing dalam pernyataan NULL. Jika ada file brosur yang sudah ada yang dihapus, kita perlu menghapus file yang ada. Namun, kami hanya akan melakukan ini jika pembaruan selesai tanpa menghasilkan pengecualian.
  • Jika SelectedValue adalah 3, maka kita ingin memastikan bahwa pengguna telah mengunggah file PDF dan kemudian menyimpannya ke sistem file serta memperbarui nilai kolom rekaman BrochurePath. Selain itu, jika ada file brosur yang sudah ada yang sedang diganti, kita perlu menghapus file sebelumnya. Namun, kami hanya akan melakukan ini jika pembaruan selesai tanpa menghasilkan pengecualian.

Langkah-langkah yang perlu dilakukan ketika RadioButtonList SelectedValue adalah 3 hampir identik dengan yang digunakan oleh penangan acara DetailsView ItemInserting. Penanganan aktivitas ini dijalankan ketika rekaman kategori baru ditambahkan dari kontrol DetailsView yang kami tambahkan di tutorial sebelumnya. Oleh karena itu, adalah kewajiban kami untuk memisahkan fungsionalitas ini menjadi metode yang terpisah. Secara khusus, saya memindahkan fungsionalitas umum ke dalam dua metode:

  • ProcessBrochureUpload(FileUpload, out bool) menerima sebagai input instans kontrol FileUpload dan nilai Boolean output yang menentukan apakah operasi hapus atau edit harus dilanjutkan atau jika harus dibatalkan karena beberapa kesalahan validasi. Metode ini mengembalikan jalur ke file yang disimpan atau null jika tidak ada file yang disimpan.
  • DeleteRememberedBrochurePath menghapus file yang ditentukan oleh path dalam variabel halaman deletedCategorysPdfPath jika deletedCategorysPdfPath bukan null.

Kode untuk kedua metode ini mengikuti. Perhatikan kesamaan antara ProcessBrochureUpload dan penanganan aktivitas DetailsView ItemInserting dari tutorial sebelumnya. Dalam tutorial ini saya telah memperbarui penanganan aktivitas DetailsView untuk menggunakan metode baru ini. Unduh kode yang terkait dengan tutorial ini untuk melihat modifikasi pada penanganan aktivitas DetailsView.

Private Function ProcessBrochureUpload _
    (BrochureUpload As FileUpload, CancelOperation As Boolean) As String
    
    CancelOperation = False    ' by default, do not cancel operation
    If BrochureUpload.HasFile Then
        ' Make sure that a PDF has been uploaded
        If String.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), _
            ".pdf", True) <> 0 Then
            
            UploadWarning.Text = _
                "Only PDF documents may be used for a category's brochure."
            UploadWarning.Visible = True
            CancelOperation = True
            Return Nothing
        End If
        Const BrochureDirectory As String = "~/Brochures/"
        Dim brochurePath As String = BrochureDirectory + BrochureUpload.FileName
        Dim fileNameWithoutExtension As String = _
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName)
        Dim iteration As Integer = 1
        While System.IO.File.Exists(Server.MapPath(brochurePath))
            brochurePath = String.Concat(BrochureDirectory, _
                fileNameWithoutExtension, "-", iteration, ".pdf")
            iteration += 1
        End While
        ' Save the file to disk and set the value of the brochurePath parameter
        BrochureUpload.SaveAs(Server.MapPath(brochurePath))
        Return brochurePath
    Else
        ' No file uploaded
        Return Nothing
    End If
End Function
Private Sub DeleteRememberedBrochurePath()
    ' Is there a file to delete?
    If deletedCategorysPdfPath IsNot Nothing Then
        System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath))
    End If
End Sub

GridView RowUpdating dan RowUpdated handler acara menggunakan ProcessBrochureUpload dan DeleteRememberedBrochurePath metode, seperti yang ditunjukkan oleh kode berikut:

Protected Sub Categories_RowUpdating _
    (sender As Object, e As GridViewUpdateEventArgs) _
    Handles Categories.RowUpdating
    
    ' Reference the RadioButtonList
    Dim BrochureOptions As RadioButtonList = _
        CType(Categories.Rows(e.RowIndex).FindControl("BrochureOptions"), _
            RadioButtonList)
    ' Get BrochurePath information about the record being updated
    Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
    Dim categoryAPI As New CategoriesBLL()
    Dim categoriesData As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categoriesData(0)
    If BrochureOptions.SelectedValue = "1" Then
        ' Use current value for BrochurePath
        If category.IsBrochurePathNull() Then
            e.NewValues("brochurePath") = Nothing
        Else
            e.NewValues("brochurePath") = category.BrochurePath
        End If
    ElseIf BrochureOptions.SelectedValue = "2" Then
        ' Remove the current brochure (set it to NULL in the database)
        e.NewValues("brochurePath") = Nothing
    ElseIf BrochureOptions.SelectedValue = "3" Then
        ' Reference the BrochurePath FileUpload control
        Dim BrochureUpload As FileUpload = _
            CType(categories.Rows(e.RowIndex).FindControl("BrochureUpload"), _
                FileUpload)
        ' Process the BrochureUpload
        Dim cancelOperation As Boolean = False
        e.NewValues("brochurePath") = _
            ProcessBrochureUpload(BrochureUpload, cancelOperation)
        e.Cancel = cancelOperation
    Else
        ' Unknown value!
        Throw New ApplicationException( _
            String.Format("Invalid BrochureOptions value, {0}", _
                BrochureOptions.SelectedValue))
    End If
    If BrochureOptions.SelectedValue = "2" OrElse _
        BrochureOptions.SelectedValue = "3" Then
        
        ' "Remember" that we need to delete the old PDF file
        If (category.IsBrochurePathNull()) Then
            deletedCategorysPdfPath = Nothing
        Else
            deletedCategorysPdfPath = category.BrochurePath
        End If
    End If
End Sub
Protected Sub Categories_RowUpdated _
    (sender As Object, e As GridViewUpdatedEventArgs) _
    Handles Categories.RowUpdated
    
    ' If there were no problems and we updated the PDF file, 
    ' then delete the existing one
    If e.Exception Is Nothing Then
        DeleteRememberedBrochurePath()
    End If
End Sub

Perhatikan bagaimana penanganan RowUpdating aktivitas menggunakan serangkaian pernyataan kondisional untuk melakukan tindakan yang sesuai berdasarkan BrochureOptions nilai properti RadioButtonList SelectedValue .

Dengan kode ini ditempatkan, Anda dapat mengedit kategori dan menggunakannya dengan brosur saat ini, tidak menggunakan brosur apapun, atau mengunggah yang baru. Lanjutkan dan cobalah. Atur RowUpdating titik henti di penanganan aktivitas dan RowUpdated untuk memahami alur kerja.

Langkah 7: Mengunggah Gambar Baru

Picture Antarmuka pengeditan ImageField dirender sebagai kotak teks yang diisi dengan nilai dari propertinya DataImageUrlField. Selama alur kerja pengeditan, GridView meneruskan parameter ke ObjectDataSource dengan nama parameter diambil dari properti ImageField DataImageUrlField dan nilai parameter adalah nilai yang dimasukkan ke dalam kotak teks di antarmuka pengeditan. Perilaku ini cocok ketika gambar disimpan sebagai file pada sistem file dan DataImageUrlField berisi URL lengkap gambar. Dengan keadaan seperti itu, antarmuka pengeditan menampilkan URL gambar di kotak teks, yang dapat diubah pengguna dan telah disimpan kembali ke database. Memang, antarmuka default ini tidak memungkinkan pengguna untuk mengunggah gambar baru, tetapi memungkinkan pengguna mengubah URL gambar dari nilai saat ini ke nilai lain. Namun, untuk tutorial ini, antarmuka pengeditan default ImageField tidak cukup karena data biner Picture disimpan langsung di dalam basis data dan properti DataImageUrlField hanya menyimpan CategoryID.

Untuk lebih memahami apa yang terjadi dalam tutorial kami ketika pengguna mengedit baris dengan ImageField, pertimbangkan contoh berikut: pengguna mengedit baris dengan CategoryID 10, menyebabkan Picture ImageField dirender sebagai kotak teks dengan nilai 10. Bayangkan bahwa pengguna mengubah nilai dalam kotak teks ini menjadi 50 dan mengklik tombol Perbarui. Postback terjadi dan GridView awalnya membuat parameter bernama CategoryID dengan nilai 50. Namun, sebelum GridView mengirim parameter ini (dan parameter CategoryName serta Description), ia menambahkan nilai-nilai dari koleksi DataKeys. Oleh karena itu, ini menimpa parameter CategoryID dengan nilai mendasar CategoryID dari baris saat ini, yaitu 10. Singkatnya, antarmuka pengeditan ImageField tidak berpengaruh pada alur kerja pengeditan untuk tutorial ini karena nama properti ImageField s DataImageUrlField dan nilai kisinya DataKey sama.

Meskipun ImageField memudahkan untuk menampilkan gambar berdasarkan data database, kami tidak ingin menyediakan kotak teks di antarmuka pengeditan. Sebaliknya, kami ingin menawarkan kontrol FileUpload yang dapat digunakan pengguna akhir untuk mengubah gambar kategori. Tidak seperti nilainya BrochurePath , untuk tutorial ini kami telah memutuskan untuk mengharuskan setiap kategori harus memiliki gambar. Oleh karena itu, kita tidak perlu memberi opsi kepada pengguna untuk menunjukkan bahwa tidak ada gambar terkait. Pengguna dapat mengunggah gambar baru atau mempertahankan gambar saat ini as-is.

Untuk menyesuaikan antarmuka pengeditan ImageField, kita perlu mengonversinya menjadi TemplateField. Dari tag pintar GridView, klik tautan Edit Kolom, pilih ImageField, dan klik tautan Konversi bidang ini menjadi TemplateField.

Mengonversi ImageField Menjadi TemplateField

Gambar 16: Mengonversi ImageField Menjadi TemplateField

Mengonversi ImageField menjadi TemplateField dengan cara ini menghasilkan TemplateField dengan dua templat. Seperti yang ditunjukkan oleh sintaks deklaratif berikut, ItemTemplate berisi kontrol Web Gambar yang properti ImageUrl-nya ditetapkan menggunakan sintaks pengikatan data berdasarkan properti DataImageUrlField dan DataImageUrlFormatString dari ImageField. TextBox pada EditItemTemplate memiliki properti Text yang terhubung ke nilai yang ditentukan oleh properti DataImageUrlField.

<asp:TemplateField>
    <EditItemTemplate>
        <asp:TextBox ID="TextBox1" runat="server" 
            Text='<%# Eval("CategoryID") %>'></asp:TextBox>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Image ID="Image1" runat="server" 
            ImageUrl='<%# Eval("CategoryID", 
                "DisplayCategoryPicture.aspx?CategoryID={0}") %>' />
    </ItemTemplate>
</asp:TemplateField>

Kita perlu memperbarui EditItemTemplate untuk menggunakan kontrol FileUpload. Dari tag pintar GridView klik tautan Edit Templat lalu pilih Picture TemplateFields EditItemTemplate dari daftar drop-down. Dalam templat, Anda akan melihat Kotak Teks menghapus ini. Selanjutnya, seret kontrol FileUpload dari Kotak Alat ke templat, atur ID ke PictureUpload. Tambahkan juga teks Untuk mengubah gambar kategori, tentukan gambar baru. Agar gambar kategori tetap sama, biarkan bidang pada templat kosong.

Menambahkan Kontrol FileUpload ke EditItemTemplate

Gambar 17: Tambahkan Kontrol FileUpload ke EditItemTemplate (Klik untuk melihat gambar ukuran penuh)

Setelah menyesuaikan antarmuka pengeditan, lihat kemajuan Anda di browser. Saat melihat baris dalam mode baca-saja, gambar kategori ditampilkan seperti sebelumnya, tetapi mengklik tombol Edit merender kolom gambar sebagai teks dengan kontrol FileUpload.

Antarmuka Pengeditan Menyertakan Kontrol FileUpload

Gambar 18: Antarmuka Pengeditan Menyertakan Kontrol FileUpload (Klik untuk melihat gambar ukuran penuh)

Ingat bahwa ObjectDataSource dikonfigurasi untuk memanggil metode CategoriesBLL dari kelas UpdateCategory yang menerima sebagai input data biner untuk gambar sebagai larik Byte. Namun, jika array ini , Nothingkelebihan beban alternatif UpdateCategory dipanggil, yang mengeluarkan UPDATE pernyataan SQL yang tidak memodifikasi Picture kolom, sehingga membiarkan gambar kategori saat ini utuh. Oleh karena itu, di penanganan aktivitas GridView RowUpdating , kita perlu mereferensikan PictureUpload kontrol FileUpload secara terprogram dan menentukan apakah file diunggah. Jika tidak diunggah, kami tidak ingin menentukan nilai untuk parameter picture. Di sisi lain, jika file diunggah dalam PictureUpload kontrol FileUpload, kami ingin memastikan bahwa file tersebut adalah file JPG. Jika ya, maka kita dapat mengirim konten binernya ke ObjectDataSource melalui picture parameter .

Seperti kode yang digunakan di Langkah 6, banyak kode yang diperlukan di sini sudah ada di penanganan aktivitas DetailsView ItemInserting . Karena itu, saya telah merefaktor fungsionalitas umum ke dalam metode baru, ValidPictureUpload, dan memperbarui pengendali peristiwa ItemInserting untuk menggunakan metode ini.

Tambahkan kode berikut ke awal penanganan aktivitas GridView RowUpdating . Penting bahwa kode ini datang sebelum kode yang menyimpan file brosur karena kami tidak ingin menyimpan brosur ke sistem file server web jika file gambar yang tidak valid diunggah.

' Reference the PictureUpload FileUpload
Dim PictureUpload As FileUpload = _
    CType(categories.Rows(e.RowIndex).FindControl("PictureUpload"), _
        FileUpload)
If PictureUpload.HasFile Then
    ' Make sure the picture upload is valid
    If ValidPictureUpload(PictureUpload) Then
        e.NewValues("picture") = PictureUpload.FileBytes
    Else
        ' Invalid file upload, cancel update and exit event handler
        e.Cancel = True
        Exit Sub
    End If
End If

Metode ini ValidPictureUpload(FileUpload) mengambil kontrol FileUpload sebagai parameter input satu-satunya dan memeriksa ekstensi file yang diunggah untuk memastikan bahwa file yang diunggah adalah JPG; itu hanya dipanggil jika file gambar diunggah. Jika tidak ada file yang diunggah, maka parameter gambar tidak diatur, dan oleh karena itu menggunakan nilai defaultnya .Nothing Jika gambar diunggah dan ValidPictureUpload mengembalikan True, picture parameter diberi data biner dari gambar yang diunggah; jika metode mengembalikan False, alur kerja pembaruan dibatalkan dan penanganan aktivitas keluar.

Kode ValidPictureUpload(FileUpload) metode, yang direfaktor dari handler event DetailsView ItemInserting, adalah sebagai berikut ini:

Private Function ValidPictureUpload(ByVal PictureUpload As FileUpload) As Boolean
    ' Make sure that a JPG has been uploaded
    If String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
        ".jpg", True) <> 0 AndAlso _
        String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
        ".jpeg", True) <> 0 Then
        
        UploadWarning.Text = _
            "Only JPG documents may be used for a category's picture."
        UploadWarning.Visible = True
        Return False
    Else
        Return True
    End If
End Function

Langkah 8: Mengganti Gambar Kategori Asli dengan JPG

Ingat bahwa gambar delapan kategori asli adalah file bitmap yang dibungkus dalam header OLE. Sekarang setelah kita menambahkan kemampuan untuk mengedit gambar rekaman yang ada, luangkan waktu sejenak untuk mengganti bitmap ini dengan JPG. Jika Anda ingin terus menggunakan gambar kategori saat ini, Anda bisa mengonversinya ke JPG dengan melakukan langkah-langkah berikut:

  1. Simpan gambar bitmap ke hard drive Anda. UpdatingAndDeleting.aspx Kunjungi halaman di browser Anda dan untuk masing-masing dari delapan kategori pertama, klik kanan pada gambar dan pilih untuk menyimpan gambar.
  2. Buka gambar di editor gambar pilihan Anda. Anda dapat menggunakan Microsoft Paint, misalnya.
  3. Simpan bitmap sebagai gambar JPG.
  4. Perbarui gambar kategori melalui antarmuka pengeditan, menggunakan file JPG.

Setelah mengedit kategori dan mengunggah gambar JPG, gambar tidak akan dirender di browser karena DisplayCategoryPicture.aspx halaman menghapus 78 byte pertama dari gambar delapan kategori pertama. Perbaiki ini dengan menghapus kode yang melakukan stripping header OLE. Setelah melakukan ini, penanganan DisplayCategoryPicture.aspx``Page_Load aktivitas seharusnya hanya memiliki kode berikut:

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim categoryID As Integer = _
        Convert.ToInt32(Request.QueryString("CategoryID"))
    ' Get information about the specified category
    Dim categoryAPI As New CategoriesBLL()
    Dim categories As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categories(0)
    ' For new categories, images are JPGs...
    ' Output HTTP headers providing information about the binary data
    Response.ContentType = "image/jpeg"
    ' Output the binary data
    Response.BinaryWrite(category.Picture)
End Sub

Nota

Antarmuka UpdatingAndDeleting.aspx untuk penyisipan dan pengeditan halaman perlu sedikit lebih banyak penyempurnaan. CategoryName Dan Description BoundFields di DetailsView dan GridView harus dikonversi menjadi TemplateFields. Karena CategoryName tidak memungkinkan penggunaan NULL, RequiredFieldValidator harus ditambahkan. Description Dan TextBox mungkin harus dikonversi menjadi Kotak Teks multibaris. Saya meninggalkan sentuhan akhir ini sebagai latihan untuk Anda.

Ringkasan

Tutorial ini melengkapi tampilan kami dalam bekerja dengan data biner. Dalam tutorial ini dan tiga sebelumnya, kita melihat bagaimana data biner dapat disimpan pada sistem file atau langsung dalam database. Pengguna menyediakan data biner ke sistem dengan memilih file dari hard drive mereka dan mengunggahnya ke server web, di mana dapat disimpan pada sistem file atau dimasukkan ke dalam database. ASP.NET 2.0 menyertakan kontrol FileUpload yang memudahkan penyediaan antarmuka seolah-olah semudah seret dan lepas. Namun, seperti yang disebutkan dalam tutorial Uploading Files , kontrol FileUpload hanya cocok untuk unggahan file yang relatif kecil, idealnya tidak melebihi megabyte. Kami juga mengeksplorasi cara mengaitkan data yang diunggah dengan model data yang mendasarinya, serta cara mengedit dan menghapus data biner dari rekaman yang ada.

Tutorial kami berikutnya mengeksplorasi berbagai teknik caching. Penembolokan menyediakan sarana untuk meningkatkan kinerja keseluruhan aplikasi dengan mengambil hasil dari operasi yang membutuhkan biaya tinggi dan menyimpannya di lokasi yang dapat diakses dengan lebih cepat.

Selamat Pemrograman!

Tentang Penulis

Scott Mitchell, penulis tujuh buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja sama dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 2.0 dalam 24 Jam. Dia dapat dijangkau di mitchell@4GuysFromRolla.com.

Ucapan terima kasih khusus kepada

Seri tutorial ini ditinjau oleh banyak peninjau yang bermanfaat. Peninjau utama untuk tutorial ini adalah Teresa Murphy. Tertarik untuk meninjau artikel MSDN saya yang akan datang? Jika demikian, hubungi saya di mitchell@4GuysFromRolla.com.