Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
tarafından Scott Mitchell
Bu öğreticide, başka bir Repeater'ın içinde yer alan bir Repeater'ın nasıl kullanılacağını inceleyeceğiz. Örnekler, iç Repeater'ın bildirim temelli ve programlı olarak nasıl doldurulacağını gösterir.
Giriş
Şablonlar, statik HTML ve veri bağlama söz dizimine ek olarak Web denetimleri ve Kullanıcı Denetimleri de içerebilir. Bu Web denetimlerinin özellikleri bildirim temelli, veri bağlama söz dizimi yoluyla atanabilir veya uygun sunucu tarafı olay işleyicilerinde program aracılığıyla erişilebilir.
Denetimleri bir şablona ekleyerek, görünüm ve kullanıcı deneyimi özelleştirilebilir ve geliştirilebilir. Örneğin, GridView Denetimindeki TemplateField'leri Kullanma öğreticisinde , bir çalışanın işe alma tarihini göstermek için TemplateField'a Takvim denetimi ekleyerek GridView görünümünü özelleştirmeyi gördük; Düzenleme ve Ekleme Arabirimlerine Doğrulama Denetimleri Ekleme veVeri Değiştirme Arabirimini Özelleştirme öğreticilerinde, doğrulama denetimleri, TextBoxes, DropDownLists ve diğer Web denetimleri ekleyerek arabirimleri düzenleme ve ekleme işlemlerini özelleştirmeyi gördük.
Şablonlar başka veri Web denetimleri de içerebilir. Başka bir ifadeyle, şablonları içinde başka bir DataList (veya Repeater, GridView veya DetailsView vb.) içeren bir DataList'imiz olabilir. Böyle bir arabirimle ilgili zorluk, uygun verileri iç veri Web denetimine bağlamaktır. ObjectDataSource kullanarak bildirim temelli seçeneklerden programlı seçeneklere kadar değişen birkaç farklı yaklaşım vardır.
Bu öğreticide, başka bir Repeater'ın içinde yer alan bir Repeater'ın nasıl kullanılacağını inceleyeceğiz. Dış Repeater, veritabanındaki her kategori için kategorinin adını ve açıklamasını görüntüleyen bir öğe içerir. Her kategori öğesinin iç Yineleyicisi, madde işaretli bir listede söz konusu kategoriye ait her ürünün bilgilerini görüntüler (bkz. Şekil 1). Örneklerimizde iç Repeater'ın bildirim temelli ve programlı olarak nasıl doldurulacağı gösterilmektedir.
Şekil 1: Her Kategori ve Ürünleri Listelenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)
1. Adım: Kategori Listesini Oluşturma
İç içe veri Web denetimlerini kullanan bir sayfa oluştururken, iç içe denetim konusunda endişelenmeden en dıştaki veri Web denetimini tasarlamayı, oluşturmayı ve test etme konusunda yararlı buluyorum. Bu nedenle, her kategorinin adını ve açıklamasını listeleyen sayfaya bir Repeater eklemek için gerekli adımları izleyerek başlayalım.
NestedControls.aspx
klasöründeki DataListRepeaterBasics
sayfasını açarak başlayın ve ID
özelliğini CategoryList
olarak ayarlayıp sayfaya bir Repeater denetimi ekleyin. Repeater'ın akıllı etiketinden adlı CategoriesDataSource
yeni bir ObjectDataSource oluşturmayı seçin.
Şekil 2: Yeni ObjectDataSource CategoriesDataSource
adını verin (Tam boyutlu görüntüyü görüntülemek için tıklayın)
ObjectDataSource'un verilerini CategoriesBLL
sınıfının GetCategories
yönteminden çekebilmesi için yapılandırın.
Şekil 3: ObjectDataSource'un CategoriesBLL
Sınıf Yöntemini Kullanacak Şekilde Yapılandırılması GetCategories
(Tam boyutlu görüntüyü görüntülemek için tıklayın)
Repeater öğesinin şablon içeriğini belirtmek için Kaynak görünümüne geçerek deklaratif söz dizimini el ile girmemiz gerekir. Bir ItemTemplate
öğesi ekleyin, bu öğede kategori adı bir <h4>
öğesinde ve kategori açıklaması bir paragraf öğesinde (<p>
) görüntülensin. Ayrıca, her kategoriyi yatay bir kuralla (<hr>
) ayıralım. Bu değişiklikleri yaptıktan sonra sayfanız Repeater ve ObjectDataSource için aşağıdakine benzer bildirim temelli söz dizimi içermelidir:
<asp:Repeater ID="CategoryList" DataSourceID="CategoriesDataSource"
EnableViewState="False" runat="server">
<ItemTemplate>
<h4><%# Eval("CategoryName") %></h4>
<p><%# Eval("Description") %></p>
</ItemTemplate>
<SeparatorTemplate>
<hr />
</SeparatorTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Şekil 4'de tarayıcı üzerinden görüntülendiğinde ilerleme durumumuz gösterilmektedir.
Şekil 4: Her Kategorinin Adı ve Açıklaması Yatay Kuralla Ayrılmış Olarak Listelenir (Tam boyutlu resmi görüntülemek için tıklayın)
2. Adım: İç İçe Ürün Yineleyicisini Ekleme
Kategori listesi tamamlandıktan sonra, bir sonraki görevimiz uygun kategoriye ait ürünlerle ilgili bilgileri görüntüleyen bir Repeater CategoryList
ItemTemplate
eklemektir. Bu iç Repeater'ın verilerini almanın birkaç yolu vardır ve bunlardan ikisi de kısa süre içinde incelenir. Şimdilik CategoryList
Repeater'ının ItemTemplate
içinde ürün Repeater'ı oluşturalım. Özellikle, ürün Yineleyicisi'nin her ürünü, ürün adı ve fiyatı dahil olmak üzere her liste öğesiyle birlikte madde işaretli bir listede görüntülemesini sağlayın.
Bu Repeat Edicisi'ni oluşturmak için, iç Repeat Edicisi'nin bildirimsel söz dizimini ve şablonlarını CategoryList
'ün ItemTemplate
'ine el ile girmemiz gerekir. Repeater s CategoryList
içine aşağıdaki işaretlemeyi ItemTemplate
ekleyin:
<asp:Repeater ID="ProductsByCategoryList" EnableViewState="False"
runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><strong><%# Eval("ProductName") %></strong>
(<%# Eval("UnitPrice", "{0:C}") %>)</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
3. Adım: Category-Specific Ürünlerini ProductsByCategoryList Repeater'a Bağlama
Bu noktada sayfayı bir tarayıcı üzerinden ziyaret ederseniz, yine de Repeater'a herhangi bir veri bağlamadığımız için ekranınız Şekil 4'tekiyle aynı görünür. Uygun ürün kayıtlarını alıp Repeater'a bağlamanın birkaç yolu vardır ve bazıları diğerlerinden daha verimlidir. Buradaki temel zorluk, belirtilen kategori için uygun ürünleri geri almaktır.
İç Repeater denetimine bağlanacak verilere, Repeater'daki CategoryList
bir ObjectDataSource ItemTemplate
aracılığıyla bildirim temelli olarak veya program aracılığıyla, ASP.NET sayfasının arka planda kod sayfasından erişilebilir. Benzer şekilde, bu veriler iç Repeater'a bildirimsel olarak bağlanabilir; iç Repeater'ın DataSourceID
özelliği aracılığıyla veya bildirimsel veri bağlama söz dizimi kullanılarak veya olay işleyicisinin CategoryList
iç Repeater'ına atıfta bulunarak, ItemDataBound
özelliğini programlı bir şekilde ayarlayıp DataSource
yöntemini çağırarak programla bağlanabilir. Şimdi bu yaklaşımların her birini inceleyelim.
ObjectDataSource Denetimi veItemDataBound
Olay İşleyicisi ile Verilere Bildirimli Olarak Erişme
Bu öğretici serisi boyunca ObjectDataSource'ı yoğun bir şekilde kullandığımızdan, bu örnekteki verilere erişmek için en doğal seçenek ObjectDataSource'a bağlı kalmaktır. sınıfı, ProductsBLL
belirtilen GetProductsByCategoryID(categoryID)
öğesine ait olan ürünler hakkında bilgi döndüren bir categoryID
yönteme sahiptir. Bu nedenle, CategoryList
Repeater'lara bir ObjectDataSource ekleyebilir ve ItemTemplate
bu sınıfın yönteminden verilerine erişecek şekilde yapılandırabiliriz.
Ne yazık ki Repeater şablonlarının Tasarım görünümü aracılığıyla düzenlenmesine izin vermez, bu nedenle bu ObjectDataSource denetimi için bildirim temelli söz dizimini el ile eklememiz gerekir. Aşağıdaki sözdizimi, bu yeni ObjectDataSource (CategoryList
) eklendikten sonra ItemTemplate
RepeaterProductsByCategoryDataSource
öğesini gösterir:
<h4><%# Eval("CategoryName") %></h4>
<p><%# Eval("Description") %></p>
<asp:Repeater ID="ProductsByCategoryList" EnableViewState="False"
DataSourceID="ProductsByCategoryDataSource" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><strong><%# Eval("ProductName") %></strong> -
sold as <%# Eval("QuantityPerUnit") %> at
<%# Eval("UnitPrice", "{0:C}") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ProductsByCategoryDataSource" runat="server"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:Parameter Name="CategoryID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
ObjectDataSource yaklaşımını kullanırken Repeater'ın ProductsByCategoryList
özelliğini ObjectDataSource'un DataSourceID
'sine ID
olarak ayarlamamız gerekir (ProductsByCategoryDataSource
). Ayrıca, ObjectDataSource'umuzun <asp:Parameter>
yöntemine geçirilecek categoryID
değerini belirten bir GetProductsByCategoryID(categoryID)
öğesi olduğuna dikkat edin. Peki bu değeri nasıl belirteceğiz? İdeal olarak, veri bağlama söz dizimini DefaultValue
kullanarak öğesinin <asp:Parameter>
özelliğini ayarlayabiliriz, örneğin:
<asp:Parameter Name="CategoryID" Type="Int32"
DefaultValue='<%# Eval("CategoryID")' />
Ne yazık ki, veri bağlama söz dizimi yalnızca olay DataBinding
içeren denetimlerde geçerlidir. Sınıfında Parameter
böyle bir olay olmadığından yukarıdaki söz dizimi geçersizdir ve çalışma zamanı hatasına neden olur.
Bu değeri ayarlamak için Repeater CategoryList
olayı için bir olay işleyicisi ItemDataBound
oluşturmamız gerekir. Olayın Repeater'a ItemDataBound
bağlı her öğe için bir kez tetiklendiğini unutmayın. Bu nedenle, bu olay dış Repeater için her tetiklendiğinde geçerli CategoryID
değerini ProductsByCategoryDataSource
ObjectDataSource'ın CategoryID
parametresine atayabiliriz.
Repeater CategoryList
olayını ItemDataBound
için aşağıdaki kodla bir olay işleyicisi oluşturun:
Protected Sub CategoryList_ItemDataBound(sender As Object, e As RepeaterItemEventArgs) _
Handles CategoryList.ItemDataBound
If e.Item.ItemType = ListItemType.AlternatingItem _
OrElse e.Item.ItemType = ListItemType.Item Then
' Reference the CategoriesRow object being bound to this RepeaterItem
Dim category As Northwind.CategoriesRow = _
CType(CType(e.Item.DataItem, System.Data.DataRowView).Row, _
Northwind.CategoriesRow)
' Reference the ProductsByCategoryDataSource ObjectDataSource
Dim ProductsByCategoryDataSource As ObjectDataSource = _
CType(e.Item.FindControl("ProductsByCategoryDataSource"), _
ObjectDataSource)
' Set the CategoryID Parameter value
ProductsByCategoryDataSource.SelectParameters("CategoryID").DefaultValue = _
category.CategoryID.ToString()
End If
End Sub
Bu olay işleyicisi, üst bilgi, alt bilgi veya ayırıcı öğe yerine bir veri öğesiyle ilgilendiğimizi güvence altına alarak başlar. Ardından, geçerli CategoriesRow
öğesine bağlı olan gerçek RepeaterItem
örneğine başvuracağız. Son olarak, ItemTemplate
içindeki ObjectDataSource'a başvuruyoruz ve CategoryID
parametre değerini geçerli CategoryID
öğesine RepeaterItem
atanıyoruz.
Bu olay işleyicisi ProductsByCategoryList
ile, her bir RepeaterItem
içindeki Repeater, RepeaterItem
kategorisi ürünlerine bağlıdır. Şekil 5'de sonuçta elde edilen çıkışın ekran görüntüsü gösterilmektedir.
Şekil 5: Dış Yineleyici her kategoriyi listeler; İçTe bu Kategorinin Ürünleri Listelenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)
Ürünlere Kategori Verilerine Göre Program Aracılığıyla Erişme
ASP.NET sayfasının kod arkası sınıfında (veya App_Code
klasöründe ya da ayrı bir Sınıf Kitaplığı projesinde), bir CategoryID
iletildiğinde uygun ürün listesini döndüren bir yöntem oluşturabiliriz. Bu, geçerli kategoriye ait ürünleri almak için bir ObjectDataSource kullanmak yerine yapılabilir. ASP.NET sayfamızın code-behind sınıfında böyle bir yöntemimiz olduğunu ve bunun GetProductsInCategory(categoryID)
olarak adlandırıldığını düşünün. Bu yöntem kullanıldığında, aşağıdaki bildirim temelli söz dizimini kullanarak geçerli kategoriye ilişkin ürünleri iç Repeater'a bağlayabiliriz:
<asp:Repeater runat="server" ID="ProductsByCategoryList" EnableViewState="False"
DataSource='<%# GetProductsInCategory(CType(Eval("CategoryID"), Integer)) %>'>
...
</asp:Repeater>
Repeater'ın DataSource
özelliği, verilerinin GetProductsInCategory(categoryID)
yönteminden geldiğini belirtmek için veri bağlama sözdizimini kullanır.
Eval("CategoryID")
türünde bir Object
değeri döndürdüğünden, nesneyi Integer
yöntemine geçirmeden önce bir GetProductsInCategory(categoryID)
'e dönüştürürüz.
CategoryID
Burada veri bağlama söz dizimi aracılığıyla erişilen CategoryID
, dış Repeater (CategoryList
) içindeki ve tablodaki kayıtlara bağlı olan Categories
olduğuna dikkat edin. Bu nedenle, CategoryID
bir veritabanı NULL
değeri olamaz, bu yüzden bir Eval
ile ilgili kontrol yapmadan DBNull
yöntemini direkt dönüştürebiliriz.
Bu yaklaşımla, bir yöntem oluşturmamız GetProductsInCategory(categoryID)
ve sağlanan categoryID
verilerine göre uygun ürün kümesini almasını sağlamalıyız. Bunu, sınıfın ProductsDataTable
ProductsBLL
yönteminin döndürdüğü GetProductsByCategoryID(categoryID)
'yı geri döndürerek yapabiliriz. Kod-arkası sınıfında GetProductsInCategory(categoryID)
yöntemini NestedControls.aspx
sayfamız için oluşturalım. Bunu aşağıdaki kodu kullanarak yapın:
Protected Function GetProductsInCategory(ByVal categoryID As Integer) _
As Northwind.ProductsDataTable
' Create an instance of the ProductsBLL class
Dim productAPI As ProductsBLL = New ProductsBLL()
' Return the products in the category
Return productAPI.GetProductsByCategoryID(categoryID)
End Function
Bu yöntem yalnızca yönteminin bir örneğini ProductsBLL
oluşturur ve yönteminin GetProductsByCategoryID(categoryID)
sonuçlarını döndürür. Yöntemin Public
veya Protected
olarak işaretlenmesi gerektiğini unutmayın; bir yöntem Private
olarak işaretlenirse, ASP.NET sayfasının deklaratif işaretlemesinden erişilemez.
Bu yeni tekniği kullanmak için bu değişiklikleri yaptıktan sonra, sayfayı bir tarayıcı üzerinden görüntülemek için biraz zaman ayırın. ObjectDataSource ve ItemDataBound
olay işleyicisi yaklaşımı kullanılırken çıkış çıkışla aynı olmalıdır (ekran görüntüsünü görmek için Şekil 5'e geri bakın).
Uyarı
ASP.NET sayfasının kod arkası sınıfında GetProductsInCategory(categoryID)
yöntemini oluşturmak gereksiz bir uğraş gibi görünebilir. Sonuçta, bu yöntem yalnızca sınıfının bir örneğini ProductsBLL
oluşturur ve yönteminin GetProductsByCategoryID(categoryID)
sonuçlarını döndürür. Neden bu yöntemi doğrudan iç Repeater'daki veri bağlama söz diziminden çağırmıyor, örneğin: DataSource='<%# ProductsBLL.GetProductsByCategoryID(CType(Eval("CategoryID"), Integer)) %>'
? Bu söz dizimi, ProductsBLL
yöntemi bir örnek yöntemi olduğundan, sınıfın geçerli uygulamamızla GetProductsByCategoryID(categoryID)
çalışmasa da, sınıfın yeni bir ProductsBLL
sınıf örneği döndürmek için statik GetProductsByCategoryID(categoryID)
bir yöntem içermesini sağlayabilir veya Instance()
'yi statik ProductsBLL
bir yöntem içerecek şekilde değiştirebilirsiniz.
Bu tür değişiklikler, ASP.NET sayfasının arka planda kod sınıfında yönteminin gereksinimini GetProductsInCategory(categoryID)
ortadan kaldırsa da, arka planda kod yöntemi, kısa süre içinde göreceğimiz gibi alınan verilerle çalışma konusunda daha fazla esneklik sağlar.
Tüm Ürün Bilgilerini Aynı Anda Alma
İncelediğimiz iki önceki teknik, sınıfın ProductsBLL
yöntemine çağrı yaparak mevcut kategori için bu ürünleri elde eder (ilk yaklaşım ObjectDataSource aracılığıyla, ikinci yaklaşım ise kod arka planda sınıftaki GetProductsByCategoryID(categoryID)
yöntem aracılığıyla). Bu yöntem her çağrıldığında, İş Mantığı Katmanı, Veri Erişim Katmanı'na ulaşarak veritabanına bir SQL deyimi gönderir. Bu SQL deyimi, Products
alanı sağlanan giriş parametresiyle eşleşen CategoryID
tablosundan satırlar döndürür.
Sistemdeki N kategori göz önüne alındığında, bu yaklaşım, kategorilerin tamamını almak için veritabanında tek bir sorgu ve her kategoriye özel ürünleri almak için N adet çağrı yapar. Ancak, yalnızca iki veritabanı çağrısında tüm gerekli verileri alabiliriz: biri kategorilerin tamamını almak ve bir diğeri de tüm ürünleri almak için. Tüm ürünlere sahip olduktan sonra, bu ürünleri filtreleyebiliriz, böylece yalnızca geçerli CategoryID
ürünle eşleşen ürünler bu kategorinin iç Repeater'ine bağlı olur.
Bu işlevi sağlamak için yalnızca ASP.NET sayfasının arka planda kod sınıfındaki yönteminde küçük bir değişiklik GetProductsInCategory(categoryID)
yapmamız gerekir. Sınıf yönteminin ProductsBLL
sonuçlarını körü körüne döndürmek yerine, bunun yerine önce GetProductsByCategoryID(categoryID)
ürünlere erişebilir (henüz erişilmemişse) ve ardından yalnızca geçirilen öğesine dayalı olarak ürünlerin filtrelenmiş görünümünü döndürebiliriz.CategoryID
Private allProducts As Northwind.ProductsDataTable = Nothing
Protected Function GetProductsInCategory(ByVal categoryID As Integer) _
As Northwind.ProductsDataTable
' First, see if we've yet to have accessed all of the product information
If allProducts Is Nothing Then
Dim productAPI As ProductsBLL = New ProductsBLL()
allProducts = productAPI.GetProducts()
End If
' Return the filtered view
allProducts.DefaultView.RowFilter = "CategoryID = " & categoryID
Return allProducts
End Function
Sayfa düzeyi değişkeninin eklenmesine dikkat edin. allProducts
Bu, tüm ürünlerle ilgili bilgileri tutar ve yöntem ilk kez GetProductsInCategory(categoryID)
çağrıldığında doldurulur. Nesnenin allProducts
oluşturulduğundan ve dolduruldığından emin olduktan sonra, yöntem DataTable sonuçlarını yalnızca belirtilenle CategoryID
eşleşen satırların CategoryID
erişilebilir olmasını sağlayacak şekilde filtreler. Bu yaklaşım, veritabanına N + 1'den ikiye kadar erişim sayısını azaltır.
Bu geliştirme, sayfanın işlenmiş işaretlemesinde herhangi bir değişiklik yapmaz ve diğer yaklaşımdan daha az kayıt getirmez. Yalnızca veritabanına yapılan çağrı sayısını azaltır.
Uyarı
Veritabanı erişimlerinin sayısının azaltılmasının performansı artıracağı konusunda sezgisel bir neden olabilir. Ancak, durum bu olmayabilir. Birçok ürününüzün CategoryID
NULL
olması durumunda, GetProducts
yöntemine yapılan çağrı, örneğin, hiçbir zaman görüntülenmeyen bazı ürünler döndürür. Üstelik, kategorilerin yalnızca bir alt kümesini gösteriyorsanız, tüm ürünlerin iade edilmesi israf olabilir, ki bu durum sayfalandırma uyguladıysanız söz konusu olabilir.
Her zaman olduğu gibi, iki tekniğin performansını analiz etmek söz konusu olduğunda, tek kesin sonuç ölçüsü uygulamanızın yaygın durum senaryoları için uyarlanmış denetimli testler çalıştırmaktır.
Özet
Bu öğreticide, bir veri Web denetimini başka bir veri denetimi içine nasıl yerleştirebileceğimizi inceledik. Özellikle, dış Repeater'ın her kategori için bir öğe gösterdiği ve iç Repeater'ın her kategori için ürünleri madde işaretli bir listede listelediği şekilde nasıl çalıştığını ele aldık. İç içe kullanıcı arabirimi oluşturmanın temel zorluğu, doğru verilere erişmek ve iç veri Web denetimine bağlamaktır. Bu öğreticide incelediğimiz çeşitli teknikler vardır; bunlardan ikisini ele aldık. İncelenen ilk yaklaşım, dış veri Web denetiminde ItemTemplate
kullanılan ObjectDataSource'un, DataSourceID
özelliği aracılığıyla iç veri Web denetimine bağlanmasıydı. İkinci teknik, ASP.NET sayfasının arka planda kod sınıfındaki bir yöntem aracılığıyla verilere erişildi. Bu yöntem daha sonra veri bağlama söz dizimi aracılığıyla iç veri Web denetimi özelliğine DataSource
bağlanabilir.
Mevcut öğreticide incelenen iç içe kullanıcı arabirimi, Repeater içinde bir başka Repeater kullanarak oluşturulmuş olsa da, bu teknikler diğer veri Web kontrollerine de uygulanabilir. Bir Repeater'ı bir GridView içinde, veya bir GridView'ı bir DataList içinde iç içe yerleştirebilirsiniz.
Mutlu Programlama!
Yazar Hakkında
Yedi ASP/ASP.NET kitabının yazarı ve 4GuysFromRolla.com kurucusu Scott Mitchell, 1998'den beri Microsoft Web teknolojileriyle çalışmaktadır. Scott bağımsız bir danışman, eğitmen ve yazar olarak çalışır. Son kitabı Sams Teach Yourself ASP.NET 24 Hours 2.0'dır. Ona adresinden mitchell@4GuysFromRolla.comulaşabilirsiniz.
Özel Teşekkürler
Bu eğitim serisi, birçok yararlı kişi tarafından incelendi. Bu öğreticinin baş gözden geçirenleri Zack Jones ve Liz Shulok oldu. Yaklaşan MSDN makalelerimi gözden geçirmek istiyor musunuz? Öyleyse, mitchell@4GuysFromRolla.com'a bir mesaj bırakın.