İç İçe Veri Web Denetimleri (C#)

Scott Mitchell tarafından

Örnek uygulamayı indirin veya PDF 'yi indirin

Bu öğreticide, başka bir yineleyici içinde iç içe geçmiş bir yineleyicisi nasıl kullanacağınızı keşfedeceğiz. Örnek olarak, iç yineleyicisi hem bildirimli hem de programlı olarak nasıl doldurulacağınız gösterilmektedir.

Giriş

Statik HTML ve veri bağlama sözdiziminin yanı sıra, Şablonlar Web denetimlerini ve kullanıcı denetimlerini de içerebilir. Bu Web denetimlerine, özelliklerinin bildirime dayalı, veri bağlama söz dizimi aracılığıyla atanması veya uygun sunucu tarafı olay işleyicilerinde program aracılığıyla erişilebilir olması olabilir.

Bir şablon içindeki denetimleri gömerek, görünüm ve Kullanıcı deneyimi üzerinde özelleştirilebilir ve geliştirilebilir. Örneğin, GridView denetim öğreticisindeki TemplateFields kullanarak , bir çalışan bir giriş tarihi göstermek üzere TemplateField içinde Takvim denetimi ekleyerek GridView s görüntüsünü özelleştirmeyi gördük. düzenlemede doğrulama denetimleri ekleme ve arabirim ekleme ve veri değişikliği arabirimi öğreticilerini özelleştirme konusunda, doğrulama denetimleri, metin kutuları, Dropdownlists ve diğer Web denetimleri ekleyerek, düzenlemenin ve ekleme arabirimlerinin nasıl özelleştirileceğini gördük.

Şablonlar, diğer veri Web denetimlerini de içerebilir. Diğer bir deyişle, şablonları içinde başka bir DataList (veya Repeater veya GridView ya da DetailsView vb.) içeren bir DataList 'i olabilir. Böyle bir arabirim ile zorluk, ilgili verileri iç veri Web denetimine bağlamadır. Kullanılabilir birkaç farklı yaklaşım vardır ve bunları programlı bir şekilde kullanarak bildirim temelli seçeneklerden farklıdır.

Bu öğreticide, başka bir yineleyici içinde iç içe geçmiş bir yineleyicisi nasıl kullanacağınızı keşfedeceğiz. Dış Yineleyici, kategori adı ve açıklamasını görüntüleyerek veritabanındaki her bir kategori için bir öğe içerecektir. Her bir kategori öğesi iç Yineleyici, bu kategoriye ait her bir ürün için bilgileri (bkz. Şekil 1) madde işaretli bir listede görüntüler. Örneklerimizde iç yineleyicisi hem bildirimli hem de programlı olarak nasıl doldurulacağınız gösterilmektedir.

Her kategori , ürünleriyle birlikte listelenir

Şekil 1: her kategori, ürünlerle birlikte 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 geçmiş veri Web denetimlerini kullanan bir sayfa oluştururken, iç içe geçmiş denetim hakkında endişelenmeden önce en dıştaki veri Web denetimini tasarlamak, oluşturmak ve test etmek faydalı olduğunu öğreniyorum. Bu nedenle, her bir kategorinin adını ve açıklamasını listeleyen sayfaya bir yineleyici eklemek için gereken adımları izleyerek başlayalım.

NestedControls.aspx sayfasını DataListRepeaterBasics klasöründen açıp sayfaya bir yineleyici denetimi ekleyerek ID özelliğini CategoryListolarak ayarlayarak başlayın. Yineleyici s akıllı etiketinden CategoriesDataSourceadlı yeni bir ObjectDataSource oluşturmayı seçin.

Yeni ObjectDataSource CategoriesDataSource adı

Şekil 2: yeni ObjectDataSource CategoriesDataSource adlandırma (tam boyutlu görüntüyü görüntülemek için tıklayın)

ObjectDataSource 'ı, verileri CategoriesBLL sınıf s GetCategories yönteminden çeker şekilde yapılandırın.

, ObjectDataSource 'un CategoriesBLL sınıfı s GetCategories metodunu kullanacak şekilde yapılandırılması

Şekil 3: CategoriesBLL sınıf s GetCategories metodunu (tam boyutlu görüntüyü görüntülemek Için tıklayın) kullanmak üzere ObjectDataSource 'ı yapılandırın

Repeater ' ın şablon içeriğini belirtmek için, kaynak görünümüne gitmemiz ve bildirim temelli sözdizimini el ile girmeniz gerekir. Kategori s adını bir <h4> öğesinde ve kategori s açıklamasını bir paragraf öğesinde (<p>) görüntüleyen bir ItemTemplate ekleyin. Ayrıca, her kategoriyi yatay bir kuralla ayıralım (<hr>). Bu değişiklikleri yaptıktan sonra sayfanız, aşağıdaki gibi yineleyici ve ObjectDataSource için bildirime dayalı sözdizimi 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 ' te bir tarayıcıdan görüntülendiklerinde ilerleme durumu gösterilmektedir.

her kategorinin adı ve açıklaması, yatay bir kuralla ayrılmış olarak listelenir

Şekil 4: her kategori adı ve açıklaması, yatay bir kuralla ayrılmış olarak listelenir (tam boyutlu görüntüyü görüntülemek için tıklayın)

2. Adım: Iç Içe geçmiş ürün yineleyicisi ekleme

Kategori listeleme tamamlandı, bir sonraki göreviniz, uygun kategoriye ait olan ürünlerle ilgili bilgileri görüntüleyen CategoryList s ItemTemplate bir yineleyici eklemektir. Bu iç Yineleyici için verileri alabildiğimiz birçok yol vardır. Bu, kısa bir süre içinde araştıracağız. Şimdilik, s ItemTemplate``CategoryList Repeater ' ın içindeki ürünleri yalnızca Yineleyici olarak oluşturalım. Özellikle, ürün yineleyicisi 'nin her bir ürünü, ürün adı ve fiyat dahil olmak üzere her bir liste öğesiyle birlikte madde işaretli bir listede görüntülemesine izin verin.

Bu yineleyicisi oluşturmak için, iç yineleyicisi 'nin bildirim temelli sözdizimini ve şablonları CategoryList s ItemTemplateiçine el ile girmemiz gerekir. Aşağıdaki biçimlendirmeyi CategoryList Yineleyici ItemTemplateiçine 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: kategoriye özgü ürünleri ProductsByCategoryList Repeater 'a bağlama

Bu noktada sayfayı bir tarayıcı aracılığıyla ziyaret ederseniz, herhangi bir veriyi yineleyicisi 'ne bağlamamız yaptığımız için ekranınızın Şekil 4 ' te olduğu gibi görünmesi gerekir. Uygun ürün kayıtlarını elde etmemiz ve bunları yineleyicisi 'ne bağlamak için birkaç yol vardır ve bunlardan bazıları diğerlerinden daha etkilidir. Buradaki ana zorluk, belirtilen kategori için uygun ürünleri geri almaktır.

İç Yineleyici denetimine bağlanacak verilere bildirimli olarak CategoryList ItemTemplateRepeater ' daki bir ObjectDataSource aracılığıyla ya da programlı olarak ASP.NET Page s arka plan kod sayfasından erişilebilir. Benzer şekilde, bu veriler iç Yineleyici ile iç yineleyicinin DataSourceID özelliği aracılığıyla ya da bildirim temelli veri bağlama söz dizimi aracılığıyla ya da program aracılığıyla CategoryList Yineleyici s ItemDataBound olay işleyicDataBind() DataSource isindeki iç Yineleyici ile başvurularak programlı bir şekilde bağlanabilir. Bu yaklaşımların her birini keşfedelim.

Bir ObjectDataSource denetimiyle veItemDataBoundolay Işleyicisiyle verilere bildirimli olarak erişme

Bu öğretici serisi genelinde ObjectDataSource 'u kapsamlı bir şekilde kullandığımızdan, bu örneğe yönelik verilere erişim için en doğal seçenek, ObjectDataSource 'u kontrol etmek için kullanılır. ProductsBLL sınıfında, belirtilen categoryID ait olan ürünler hakkında bilgi döndüren bir GetProductsByCategoryID(categoryID) yöntemi vardır. Bu nedenle, CategoryList Yineleyici ItemTemplate bir ObjectDataSource ekleyebiliyoruz ve bu sınıf s yönteminden verilerine erişecek şekilde yapılandırabiliriz.

Ne yazık ki Yineleyici, ş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özdizimini el ile eklememiz gerekir. Aşağıdaki sözdizimi, bu yeni ObjectDataSource eklendikten sonra ItemTemplate CategoryList yineleyicisi 'ni gösterir (ProductsByCategoryDataSource):

<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, ProductsByCategoryList Yineleyici s DataSourceID özelliğini ObjectDataSource 'un (ProductsByCategoryDataSource) ID ayarlaması gerekir. Ayrıca, ObjectDataSource 'lerimizin GetProductsByCategoryID(categoryID) yöntemine geçirilecek categoryID değerini belirten bir <asp:Parameter> öğesi olduğuna dikkat edin. Ancak bu değeri nasıl belirttik? İdeal olarak, aşağıdaki gibi, veri bağlama söz dizimini kullanarak <asp:Parameter> öğesinin DefaultValue özelliğini ayarlayabiliriz:

<asp:Parameter Name="CategoryID" Type="Int32"
     DefaultValue='<%# Eval("CategoryID")' />

Ne yazık ki, veri bağlama söz dizimi yalnızca DataBinding olayına sahip denetimlerde geçerlidir. Parameter sınıfında böyle bir olay yok ve bu nedenle yukarıdaki sözdizimi geçersizdir ve bir çalışma zamanı hatasına neden olur.

Bu değeri ayarlamak için, CategoryList Repeater s ItemDataBound olayı için bir olay işleyicisi oluşturuyoruz. Yineleyicisi 'ne bağlanan her öğe için ItemDataBound olayının bir kez harekete geçirilir. Bu nedenle, bu olay dış Yineleyici için her tetiklendiğinde, geçerli CategoryID değerini ProductsByCategoryDataSource ObjectDataSource s CategoryID parametresine atayabiliriz.

Aşağıdaki kodla CategoryList Repeater s ItemDataBound olayı için bir olay işleyicisi oluşturun:

protected void CategoryList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.AlternatingItem ||
        e.Item.ItemType == ListItemType.Item)
    {
        // Reference the CategoriesRow object being bound to this RepeaterItem
        Northwind.CategoriesRow category =
            (Northwind.CategoriesRow)((System.Data.DataRowView)e.Item.DataItem).Row;
        // Reference the ProductsByCategoryDataSource ObjectDataSource
        ObjectDataSource ProductsByCategoryDataSource =
            (ObjectDataSource)e.Item.FindControl("ProductsByCategoryDataSource");
        // Set the CategoryID Parameter value
        ProductsByCategoryDataSource.SelectParameters["CategoryID"].DefaultValue =
            category.CategoryID.ToString();
    }
}

Bu olay işleyicisi, üst bilgi, alt bilgi veya ayırıcı öğe yerine bir veri öğesiyle ilgilenmemiz sağlanarak başlar. Ardından, geçerli RepeaterItemzaten bağlanan gerçek CategoriesRow örneğine başvuruyoruz. Son olarak, ItemTemplate ObjectDataSource 'a başvurduk ve CategoryID parametre değerini geçerli RepeaterItem``CategoryID atamalısınız.

Bu olay işleyicisiyle, her RepeaterItem ProductsByCategoryList yineleyicisi RepeaterItem s kategorisindeki bu ürünlere bağlanır. Şekil 5 elde edilen çıktının ekran görüntüsünü gösterir.

Dış Yineleyici her kategoriyi listeler; Inner bir kategori için ürünleri listeler

Şekil 5: dış Yineleyici her kategoriyi listeler; Inner bir kategori için ürünleri listeler (tam boyutlu görüntüyü görüntülemek Için tıklayın)

Program aracılığıyla kategoriye göre ürünlere erişme

Geçerli kategori için ürünleri almak üzere bir ObjectDataSource kullanmak yerine, bir CategoryIDgeçirildiğinde uygun ürün kümesini döndüren ASP.NET Page s arka plan kod sınıfında (veya App_Code klasöründe veya ayrı bir sınıf kitaplığı projesinde) bir yöntem oluşturarız. ASP.NET Page s kod arkasında bir yöntem olduğunu ve GetProductsInCategory(categoryID)adlandırdığını düşünün. Bu yöntemle birlikte, aşağıdaki bildirime dayalı sözdizimini kullanarak geçerli kategorinin ürünlerini iç Yineleyici olarak bağlayabiliriz:

<asp:Repeater runat="server" ID="ProductsByCategoryList" EnableViewState="False"
      DataSource='<%# GetProductsInCategory((int)(Eval("CategoryID"))) %>'>
  ...
</asp:Repeater>

Repeater s DataSource özelliği, verilerinin GetProductsInCategory(categoryID) yönteminden geldiğini göstermek için DataBinding sözdizimini kullanır. Eval("CategoryID") Objecttüründe bir değer döndürdüğünden, nesneyi GetProductsInCategory(categoryID) yöntemine geçirmeden önce bir Integer hale getiririz. Veri bağlama söz dizimi aracılığıyla buraya erişildiğine CategoryID, bu, Categories tablosundaki kayıtlarla bağlantılı olan dış yineleyici (CategoryList) CategoryID. Bu nedenle CategoryID bir veritabanı NULL değeri olmadığını biliyoruz. Bu, neden bir DBNullile ilgilendiğinizi kontrol etmeden Eval metodunu daha da düzenleyebilir.

Bu yaklaşımda GetProductsInCategory(categoryID) yöntemi oluşturuyoruz ve sağlanan categoryID verilen uygun ürün kümesini almamız gerekir. Bunu, ProductsBLL sınıfı s GetProductsByCategoryID(categoryID) metodu tarafından döndürülen ProductsDataTable döndürerek yapabiliriz. NestedControls.aspx sayfamız için arka plan kod sınıfında GetProductsInCategory(categoryID) yöntemi oluşturalım. Aşağıdaki kodu kullanarak bunu yapın:

protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
    // Create an instance of the ProductsBLL class
    ProductsBLL productAPI = new ProductsBLL();
    // Return the products in the category
    return productAPI.GetProductsByCategoryID(categoryID);
}

Bu yöntem, yalnızca ProductsBLL yönteminin bir örneğini oluşturur ve GetProductsByCategoryID(categoryID) yönteminin sonuçlarını döndürür. Metodun Public veya Protectedolarak işaretlenmesi gerektiğini unutmayın. Yöntem Privateişaretlenmişse, ASP.NET sayfa s bildirime dayalı biçimlendirmeden erişilebilir olmayacaktır.

Bu yeni tekniği kullanmak için bu değişiklikleri yaptıktan sonra, sayfayı bir tarayıcıdan görüntülemek için bir dakikanızı ayırın. ObjectDataSource ve ItemDataBound olay işleyicisi yaklaşımı kullanılırken çıkış ile aynı olmalıdır (ekran görüntüsünü görmek için Şekil 5 ' e geri dönün).

Note

ASP.NET Page s arka plan kod sınıfında GetProductsInCategory(categoryID) yöntemi oluşturmak için Busi işi gibi görünebilir. All, bu yöntem ProductsBLL sınıfının bir örneğini oluşturur ve GetProductsByCategoryID(categoryID) yönteminin sonuçlarını döndürür. Bu yöntemi neden yalnızca iç Yineleyici içindeki veri bağlama sözdiziminden (DataSource='<%# ProductsBLL.GetProductsByCategoryID((int)(Eval("CategoryID"))) %>'gibi) doğrudan çağıramadınız. Bu söz dizimi, ProductsBLL sınıfının geçerli uygulamamız ile çalışmasa da (GetProductsByCategoryID(categoryID) yöntemi bir örnek yöntemi olduğundan), ProductsBLL statik bir GetProductsByCategoryID(categoryID) metodu içerecek şekilde değiştirebilir veya Instance() sınıfının yeni bir örneğini döndürmek için sınıfın statik ProductsBLL yöntemini içermesini sağlayabilirsiniz.

Bu değişiklikler, ASP.NET sayfa kodu arka plan kodundaki GetProductsInCategory(categoryID) yöntemi gereksinimini ortadan kaldıracak, ancak arka plan kod sınıfı yöntemi, kısa süre içinde göreceğiniz şekilde, alınan verilerle çalışma konusunda daha fazla esneklik sağlar.

Tüm ürün bilgilerini aynı anda alma

ProductsBLL sınıf s GetProductsByCategoryID(categoryID) yöntemine bir çağrı yaparak inceliyoruz ve bu ürünlerin geçerli kategori için bu ürünleri elde ettiğimiz iki performans tekniği (ilk yaklaşım bir ObjectDataSource tarafından, ikinciden kod arkasındaki GetProductsInCategory(categoryID) yöntemi aracılığıyla). Bu yöntemin her çağrılışında Iş mantığı katmanı, CategoryID alanı sağlanan giriş parametresiyle eşleşen Products tablosundan satırları döndüren bir SQL ifadesiyle veritabanını sorgulayan veri erişim katmanına geri döner.

Sistemde bu yaklaşım, tüm kategorileri almak için tek bir veritabanı sorgusuna yönelik n + 1 çağrıları ve her kategoriye özgü ürünleri almak için n çağrısı sağlar. Ancak, tüm gerekli verileri yalnızca iki veritabanında alabilir ve tüm ürünlerin tümünü almak için bir çağrı yapın. Tüm ürünleri edindikten sonra, bu ürünleri yalnızca geçerli CategoryID eşleşen ürünlerin bu kategoriye ait iç Yineleyici ile bağlanacağı şekilde filtreleyebiliriz.

Bu işlevi sağlamak için, ASP.NET Page s Code-Behind sınıfındaki GetProductsInCategory(categoryID) yönteminde yalnızca küçük bir değişiklik yapmanız gerekir. ProductsBLL sınıf s GetProductsByCategoryID(categoryID) yönteminin sonuçlarını bir adım adım geri döndürmek yerine, bu ürünlerin tümüne ilk kez erişebiliriz (önceden erişilmemişse) ve ardından, geçirilen CategoryIDgöre yalnızca ürünlerin filtrelenmiş görünümünü geri alabilirsiniz.

private Northwind.ProductsDataTable allProducts = null;
protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
    // First, see if we've yet to have accessed all of the product information
    if (allProducts == null)
    {
        ProductsBLL productAPI = new ProductsBLL();
        allProducts = productAPI.GetProducts();
    }
    // Return the filtered view
    allProducts.DefaultView.RowFilter = "CategoryID = " + categoryID;
    return allProducts;
}

Sayfa düzeyi değişkeninin eklenmesini allProducts. Bu, tüm ürünlerle ilgili bilgileri barındırır ve GetProductsInCategory(categoryID) yöntemi ilk kez çağrıldığında doldurulur. allProducts nesnesinin oluşturulup doldurulduğundan emin olduktan sonra, yöntemi DataTable s sonuçlarını yalnızca CategoryID belirtilen CategoryID eşleşen satırlara erişilebilir olacak şekilde filtreler. Bu yaklaşım, veritabanına N + 1 ' den iki kez erişilme sayısını azaltır.

Bu geliştirme, sayfanın işlenmiş biçimlendirmesinde herhangi bir değişikliğe neden olmaz, ne de diğer yaklaşımdan daha az kayıt geri getirir. Yalnızca veritabanına yapılan çağrıların sayısını azaltır.

Note

Bunlardan biri, veritabanı erişimlerini azaltmak assuredly performansı artırmak için çok sayıda neden olabilir. Ancak, bu durum olmayabilir. CategoryID NULLolan çok sayıda ürünsahipseniz, örneğin GetProducts yöntemine yapılan çağrı, hiçbir şekilde görüntülenmeyen bir dizi ürünü geri döndürür. Üstelik, yalnızca kategorilerin bir alt kümesini gösteriyorsanız, bu, sayfalama uygulamış olmanız durumunda olabilecek tüm ürünlerin döndürülmesi beklenebilir.

Her zaman olduğu gibi, iki tekninin performansını analiz etmek için tek SureFire ölçüsü, uygulamanızın ortak olay senaryolarınız için uyarlanmış denetimli testleri çalıştırmalıdır.

Özet

Bu öğreticide, bir veri Web denetiminin başka bir şekilde nasıl iç yineleyicisi olduğunu, özellikle de bir dış yineleyicisi 'nin bir madde işaretli liste içindeki her bir kategorinin ürünlerini listeleme iç Yineleyici olan her kategori için bir öğe göstermesini gördük. İç içe bir kullanıcı arabirimi oluşturmanın ana zorluğu, doğru verileri iç veri Web denetimine bağlama ve bunlara bağlama konusunda yer alır. Bu öğreticide incelenen, iki farklı teknik mevcuttur. İlk yaklaşım, DataSourceID özelliği aracılığıyla iç veri Web denetimine bağlanan ItemTemplate dış veri Web denetimindeki bir ObjectDataSource kullandı. İkinci teknikte, ASP.NET Page s arka plan kod sınıfındaki bir yöntem aracılığıyla verilere erişilir. Bu yöntem daha sonra veri bağlama söz dizimi aracılığıyla iç veri Web denetimi s DataSource özelliğine bağlanabilir.

Bu öğreticide incelenen iç içe geçmiş kullanıcı arabirimi, bir yineleyici içinde iç içe geçmiş bir yineleyici kullanıyordu, bu teknikler diğer veri Web denetimlerine genişletilebilir. Bir ya da bir GridView içinde bir bir yineleyici iç içe veya bir GridView içinde bir GridView oluşturabilirsiniz.

Programlamanın kutlu olsun!

Yazar hakkında

4GuysFromRolla.com 'in, Scott Mitchell, yedi ASP/ASP. net books ve 'in yazarı, 1998 sürümünden bu yana Microsoft Web teknolojileriyle çalışmaktadır. Scott bağımsız danışman, Trainer ve yazıcı olarak çalışıyor. En son kitabı, 24 saat içinde ASP.NET 2,0 kendi kendinize eğitimister. mitchell@4GuysFromRolla.comadresinden erişilebilir . ya da blog aracılığıyla http://ScottOnWriting.NETbulabilirsiniz.

Özel olarak teşekkürler

Bu öğretici serisi birçok yararlı gözden geçirenler tarafından incelendi. Bu öğreticide lider gözden geçirenler Zack Jones ve Liz Shulok. Yaklaşan MSDN makalelerimi gözden geçiriyor musunuz? Öyleyse, benimitchell@4GuysFromRolla.combir satır bırakın .