Formatowanie elementów DataList i Repeater na podstawie danych (VB)
Autor : Scott Mitchell
W tym samouczku omówimy przykłady formatowania wyglądu kontrolek DataList i Repeater przy użyciu funkcji formatowania w szablonach lub obsługi zdarzenia DataBound.
Wprowadzenie
Jak pokazano w poprzednim samouczku, lista DataList oferuje wiele właściwości związanych ze stylem, które wpływają na jej wygląd. W szczególności pokazano, jak przypisać domyślne klasy CSS do właściwości DataList s HeaderStyle
, ItemStyle
, AlternatingItemStyle
i SelectedItemStyle
. Oprócz tych czterech właściwości lista DataList zawiera wiele innych właściwości związanych ze stylem, takich jak Font
, ForeColor
, BackColor
i BorderWidth
, aby wymienić kilka. Kontrolka Repeater nie zawiera żadnych właściwości związanych ze stylem. Wszelkie takie ustawienia stylu należy wprowadzić bezpośrednio w znacznikach w szablonach repeaterów.
Często jednak sposób formatowania danych zależy od samych danych. Na przykład podczas wyświetlania produktów możemy chcieć wyświetlić informacje o produkcie w jasnoszarym kolorze czcionki, jeśli nie zostanie przerwana, lub możemy zaznaczyć UnitsInStock
wartość, jeśli jest to zero. Jak pokazano w poprzednich samouczkach, kontrolki GridView, DetailsView i FormView oferują dwa różne sposoby formatowania ich wyglądu na podstawie danych:
- Zdarzenie
DataBound
tworzy procedurę obsługi zdarzeń dla odpowiedniegoDataBound
zdarzenia, które jest uruchamiane po powiązaniu danych z każdym elementem (dla kontrolki GridView byłoRowDataBound
to zdarzenie; dla elementu DataList i Repeater jest toItemDataBound
zdarzenie). W tej procedurze obsługi zdarzeń tylko powiązane dane można zbadać i podjąć decyzje dotyczące formatowania. Przeanalizowaliśmy tę technikę w samouczku Custom Formatting Based Upon Data (Formatowanie niestandardowe oparte na danych ). - Funkcje formatowania w szablonach w przypadku używania elementów TemplateFields w kontrolkach DetailsView lub GridView albo szablonu w kontrolce FormView możemy dodać funkcję formatowania do klasy kodowej strony ASP.NET, warstwy logiki biznesowej lub dowolnej innej biblioteki klas dostępnej z poziomu aplikacji internetowej. Ta funkcja formatowania może akceptować dowolną liczbę parametrów wejściowych, ale musi zwrócić kod HTML do renderowania w szablonie. Funkcje formatowania zostały po raz pierwszy zbadane w samouczku Using TemplateFields w kontrolce GridView .
Obie te techniki formatowania są dostępne za pomocą kontrolek DataList i Repeater. W tym samouczku omówimy przykłady przy użyciu obu technik dla obu kontrolek.
Korzystanie z programu obsługi zdarzeńItemDataBound
Gdy dane są powiązane z elementem DataList, z kontrolki źródła danych lub przez programowe przypisywanie danych do właściwości kontrolki DataSource
i wywoływanie jej DataBind()
metody, wyzwalane jest zdarzenie DataList DataBinding
, wyliczone źródło danych i każdy rekord danych jest powiązany z listą DataList. Dla każdego rekordu w źródle danych element DataList tworzy DataListItem
obiekt, który jest następnie powiązany z bieżącym rekordem. Podczas tego procesu lista DataList zgłasza dwa zdarzenia:
ItemCreated
uruchamia się po utworzeniuDataListItem
ItemDataBound
jest uruchamiany po powiązaniu bieżącego rekordu zDataListItem
W poniższych krokach opisano proces powiązania danych dla kontrolki DataList.
Zdarzenie DataList jest
DataBinding
wyzwalaneDane są powiązane z listą danych
Dla każdego rekordu w źródle danych
- Tworzenie
DataListItem
obiektu - Wyzwol zdarzenie
ItemCreated
- Wiązanie rekordu z rekordem
DataListItem
- Wyzwol zdarzenie
ItemDataBound
- Dodawanie elementu
DataListItem
do kolekcjiItems
- Tworzenie
Po powiązaniu danych z kontrolką Repeater przechodzi ona przez dokładnie tę samą sekwencję kroków. Jedyną różnicą jest to, że zamiast DataListItem
tworzonych wystąpień, repeater używa RepeaterItem
s.
Uwaga
Czytelnik może zauważyć niewielką anomalię między sekwencją kroków, które występują, gdy element DataList i Repeater są powiązane z danymi, a gdy element GridView jest powiązany z danymi. Na końcu procesu powiązania danych element GridView zgłasza DataBound
zdarzenie, jednak kontrolka DataList ani Repeater nie ma takiego zdarzenia. Jest to spowodowane tym, że kontrolki DataList i Repeater zostały utworzone z powrotem w przedziale czasu ASP.NET 1.x, zanim wzorzec procedury obsługi zdarzeń przed i po poziomie stał się powszechny.
Podobnie jak w przypadku kontrolki GridView, jedną z opcji formatowania na podstawie danych jest utworzenie programu obsługi zdarzeń dla ItemDataBound
zdarzenia. Ta procedura obsługi zdarzeń sprawdzi dane, które zostały właśnie powiązane z DataListItem
kontrolką lub RepeaterItem
, i wpłynie na formatowanie kontrolki zgodnie z potrzebami.
W przypadku kontrolki DataList zmiany formatowania dla całego elementu można zaimplementować przy użyciu DataListItem
właściwości związanych ze stylem s, które obejmują standard Font
, , ForeColor
BackColor
, CssClass
i tak dalej. Aby wpłynąć na formatowanie określonych kontrolek sieci Web w szablonie dataList, musimy programowo uzyskać dostęp i zmodyfikować styl tych kontrolek sieci Web. Zobaczyliśmy, jak to zrobić z powrotem w samouczku Custom Formatting Based Upon Data (Formatowanie niestandardowe oparte na danych ). Podobnie jak kontrolka RepeaterItem
Repeater, klasa nie ma właściwości związanych ze stylem, dlatego wszystkie zmiany związane ze stylem RepeaterItem
wprowadzone w ItemDataBound
programie obsługi zdarzeń muszą być wykonywane programowo przez programowe uzyskiwanie dostępu do kontrolek sieci Web i aktualizowanie ich w szablonie.
ItemDataBound
Ponieważ technika formatowania elementów DataList i Repeater jest praktycznie identyczna, nasz przykład koncentruje się na korzystaniu z elementu DataList.
Krok 1. Wyświetlanie informacji o produkcie na liście danych
Zanim zaczniemy martwić się o formatowanie, najpierw utwórzmy stronę, która używa elementu DataList do wyświetlania informacji o produkcie. W poprzednim samouczku utworzyliśmy element DataList, którego ItemTemplate
każda nazwa produktu, kategoria, dostawca, ilość na jednostkę i cena. Powtórzmy tę funkcję w tym samouczku. W tym celu można utworzyć ponownie obiekt DataList i jego obiektDataSource od podstaw lub skopiować te kontrolki ze strony utworzonej w poprzednim samouczku (Basics.aspx
) i wkleić je do strony na potrzeby tego samouczka (Formatting.aspx
).
Po zreplikacji funkcji DataList i ObjectDataSource z Basics.aspx
do Formatting.aspx
pliku poświęć chwilę, aby zmienić właściwość s ID
DataList z DataList1
na bardziej opisową ItemDataBoundFormattingExample
. Następnie wyświetl element DataList w przeglądarce. Jak pokazano na rysunku 1, jedyną różnicą formatowania między poszczególnymi produktami jest to, że kolor tła zmienia się.
Rysunek 1. Produkty są wyświetlane w kontrolce DataList (kliknij, aby wyświetlić obraz pełnowymiarowy)
W tym samouczku sformatujmy element DataList tak, aby wszystkie produkty o cenie niższej niż 20,00 USD miały zarówno nazwę, jak i cenę jednostkową wyróżnioną kolorem żółtym.
Krok 2. Programowe określanie wartości danych w programie obsługi zdarzeń ItemDataBound
Ponieważ tylko te produkty z ceną poniżej 20,00 USD będą miały zastosowane niestandardowe formatowanie, musimy mieć możliwość określenia ceny każdego produktu. Podczas wiązania danych z elementem DataList lista DataList wylicza rekordy w źródle danych, a dla każdego rekordu tworzy DataListItem
wystąpienie, wiążąc rekord źródła danych z rekordem DataListItem
. Po powiązaniu danych określonego rekordu z bieżącym DataListItem
obiektem zostanie wyzwolone zdarzenie datalist ItemDataBound
. Możemy utworzyć procedurę obsługi zdarzeń dla tego zdarzenia, aby sprawdzić wartości danych dla bieżącej DataListItem
wartości i, na podstawie tych wartości, wprowadzić wszelkie niezbędne zmiany formatowania.
ItemDataBound
Utwórz zdarzenie dla elementu DataList i dodaj następujący kod:
Protected Sub ItemDataBoundFormattingExample_ItemDataBound _
(sender As Object, e As DataListItemEventArgs) _
Handles ItemDataBoundFormattingExample.ItemDataBound
If e.Item.ItemType = ListItemType.Item OrElse _
e.Item.ItemType = ListItemType.AlternatingItem Then
' Programmatically reference the ProductsRow instance
' bound to this DataListItem
Dim product As Northwind.ProductsRow = _
CType(CType(e.Item.DataItem, System.Data.DataRowView).Row, _
Northwind.ProductsRow)
' See if the UnitPrice is not NULL and less than $20.00
If Not product.IsUnitPriceNull() AndAlso product.UnitPrice < 20 Then
' TODO: Highlight the product's name and price
End If
End If
End Sub
Chociaż koncepcja i semantyka obsługi zdarzeń usługi DataList ItemDataBound
są takie same jak te, które są używane przez program obsługi zdarzeń GridView RowDataBound
w samouczku Custom Formatting Based On Data (Niestandardowe formatowanie oparte na danych ), składnia różni się nieco. ItemDataBound
Gdy zdarzenie jest uruchamiane, DataListItem
po prostu powiązane dane są przekazywane do odpowiedniej procedury obsługi zdarzeń za pośrednictwem e.Item
(zamiast e.Row
, podobnie jak w przypadku programu obsługi zdarzeń GridViewRowDataBound
). Procedura obsługi zdarzeń elementu DataList jest ItemDataBound
uruchamiana dla każdego wiersza dodanego do listy DataList, w tym wierszy nagłówka, wierszy stopki i wierszy separatora. Jednak informacje o produkcie są powiązane tylko z wierszami danych. W związku z tym w przypadku korzystania ze ItemDataBound
zdarzenia w celu sprawdzenia danych powiązanych z listą DataList musimy najpierw upewnić się, że pracujemy z elementem danych. Można to zrobić, sprawdzając DataListItem
właściwość sItemType
, która może mieć jedną z następujących ośmiu wartości:
AlternatingItem
EditItem
Footer
Header
Item
Pager
SelectedItem
Separator
Item
AlternatingItem``DataListItem
Elementy danych dataList i są makijażem elementów danych. Zakładając, że pracujemy z elementem Item
lub AlternatingItem
, uzyskujemy dostęp do rzeczywistego ProductsRow
wystąpienia powiązanego z bieżącym DataListItem
elementem . Właściwość DataListItem
s DataItem
zawiera odwołanie do DataRowView
obiektu, którego Row
właściwość zawiera odwołanie do rzeczywistego ProductsRow
obiektu.
Następnie sprawdzimy ProductsRow
właściwość wystąpienia UnitPrice
. Ponieważ pole Tabeli UnitPrice
Products zezwala na NULL
wartości, przed podjęciem próby uzyskania dostępu UnitPrice
do właściwości należy najpierw sprawdzić, czy ma NULL
wartość przy użyciu IsUnitPriceNull()
metody . Jeśli wartość nie NULL
jest wartością UnitPrice
, sprawdzamy, czy jest mniejsza niż 20,00 USD. Jeśli jest rzeczywiście poniżej 20,00 USD, musimy zastosować formatowanie niestandardowe.
Krok 3. Wyróżnianie nazwy produktu i ceny
Gdy wiemy, że cena produktu jest mniejsza niż $20.00, wszystko, co pozostaje, to podkreślić jego nazwę i cenę. Aby to osiągnąć, musimy najpierw programowo odwołać się do kontrolek Etykieta w ItemTemplate
tym, które wyświetlają nazwę i cenę produktu. Następnie musimy wyświetlić żółte tło. Te informacje o formatowaniu można stosować bezpośrednio, modyfikując właściwości Etykiety BackColor
(LabelID.BackColor = Color.Yellow
); jednak w idealnym przypadku wszystkie kwestie związane z wyświetlaniem powinny być wyrażane za pomocą kaskadowych arkuszy stylów. W rzeczywistości mamy już arkusz stylów, który zapewnia żądane formatowanie zdefiniowane w Styles.css
- AffordablePriceEmphasis
programie , który został utworzony i omówiony w samouczku Niestandardowe formatowanie na podstawie danych .
Aby zastosować formatowanie, wystarczy ustawić dwie właściwości kontrolek CssClass
sieci Web etykiet na AffordablePriceEmphasis
, jak pokazano w poniższym kodzie:
' Highlight the product name and unit price Labels
' First, get a reference to the two Label Web controls
Dim ProductNameLabel As Label = CType(e.Item.FindControl("ProductNameLabel"), Label)
Dim UnitPriceLabel As Label = CType(e.Item.FindControl("UnitPriceLabel"), Label)
' Next, set their CssClass properties
If ProductNameLabel IsNot Nothing Then
ProductNameLabel.CssClass = "AffordablePriceEmphasis"
End If
If UnitPriceLabel IsNot Nothing Then
UnitPriceLabel.CssClass = "AffordablePriceEmphasis"
End If
Po zakończeniu ItemDataBound
obsługi zdarzeń ponownie przejdź do Formatting.aspx
strony w przeglądarce. Jak pokazano na rysunku 2, te produkty o cenie poniżej 20,00 USD mają wyróżnioną zarówno nazwę, jak i cenę.
Rysunek 2. Te produkty mniejsze niż 20,00 USD są wyróżnione (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Uwaga
Ponieważ element DataList jest renderowany jako html <table>
, jego DataListItem
wystąpienia mają właściwości związane ze stylem, które można ustawić w celu zastosowania określonego stylu do całego elementu. Jeśli na przykład chcemy wyróżnić cały element żółty, gdy jego cena była mniejsza niż 20,00 USD, możemy zastąpić kod, który odwołuje się do etykiet i ustawić ich CssClass
właściwości następującym wierszem kodu: e.Item.CssClass = "AffordablePriceEmphasis"
(zobacz Rysunek 3).
S RepeaterItem
, które tworzą kontrolkę Repeater, jednak nie oferują takich właściwości na poziomie stylu. W związku z tym zastosowanie niestandardowego formatowania do repeatera wymaga zastosowania właściwości stylu do kontrolek sieci Web w szablonach repeater, podobnie jak na rysunku 2.
Rysunek 3. Cała pozycja produktu jest wyróżniona dla produktów poniżej 20,00 USD (kliknij, aby wyświetlić obraz pełnowymiarowy)
Używanie funkcji formatowania z poziomu szablonu
W samouczku Using TemplateFields in the GridView Control (Używanie pól szablonów w kontrolce GridView ) pokazano, jak używać funkcji formatowania w elemecie GridView TemplateField w celu zastosowania niestandardowego formatowania na podstawie danych powiązanych z wierszami kontrolki GridView. Funkcja formatowania to metoda, którą można wywołać z szablonu i zwraca kod HTML, który ma być emitowany w jego miejscu. Funkcje formatowania mogą znajdować się w klasie ASP.NET stronicowej lub mogą być scentralizowane w plikach klas w App_Code
folderze lub w osobnym projekcie biblioteki klas. Przeniesienie funkcji formatowania z klasy ASP.NET s page-behind jest idealne, jeśli planujesz używać tej samej funkcji formatowania na wielu stronach ASP.NET lub w innych aplikacjach internetowych ASP.NET.
Aby zademonstrować funkcje formatowania, informacje o produkcie zawierają tekst [DISCONTINUED] obok nazwy produktu, jeśli zostanie przerwany. Ponadto, załóżmy, że cena jest wyróżniona żółtą, jeśli jest mniejsza niż 20,00 USD (tak jak w przykładzie ItemDataBound
obsługi zdarzeń); jeśli cena wynosi 20,00 USD lub wyższa, nie wyświetlmy rzeczywistej ceny, ale zamiast tego tekst, zadzwoń do oferty cenowej. Rysunek 4 przedstawia zrzut ekranu przedstawiający listę produktów z zastosowanymi regułami formatowania.
Rysunek 4. W przypadku drogich produktów cena jest zastępowana tekstem, wywołaj ofertę cenową (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 1. Tworzenie funkcji formatowania
W tym przykładzie potrzebujemy dwóch funkcji formatowania, które wyświetlają nazwę produktu wraz z tekstem [DISCONTINUED], w razie potrzeby, a drugi, który wyświetla wyróżnioną cenę, jeśli jest mniejsza niż 20,00 USD lub tekst, zadzwoń do oferty cenowej w przeciwnym razie. Utwórzmy te funkcje w klasie ASP.NET stron kodowych i nadajmy im DisplayProductNameAndDiscontinuedStatus
nazwę i DisplayPrice
. Obie metody muszą zwrócić kod HTML do renderowania jako ciąg, a oba metody muszą być oznaczone Protected
(lub Public
) w celu wywołania z części składni deklaratywnej strony ASP.NET. Kod dla tych dwóch metod jest następujący:
Protected Function DisplayProductNameAndDiscontinuedStatus _
(productName As String, discontinued As Boolean) As String
' Return just the productName if discontinued is false
If Not discontinued Then
Return productName
Else
' otherwise, return the productName appended with the text "[DISCONTINUED]"
Return String.Concat(productName, " [DISCONTINUED]")
End If
End Function
Protected Function DisplayPrice(product As Northwind.ProductsRow) As String
' If price is less than $20.00, return the price, highlighted
If Not product.IsUnitPriceNull() AndAlso product.UnitPrice < 20 Then
Return String.Concat("<span class="AffordablePriceEmphasis">", _
product.UnitPrice.ToString("C"), "</span>")
Else
' Otherwise return the text, "Please call for a price quote"
Return "<span>Please call for a price quote</span>"
End If
End Function
Należy pamiętać, że DisplayProductNameAndDiscontinuedStatus
metoda akceptuje wartości pól danych i discontinued
jako wartości productName
skalarne, natomiast DisplayPrice
metoda akceptuje ProductsRow
wystąpienie (a nie wartość skalarnąunitPrice
). Jedną z metod będzie działać; jeśli jednak funkcja formatowania współpracuje z wartościami skalarnymi, które mogą zawierać wartości bazy danych NULL
(takie jak UnitPrice
; ani ProductName
nie Discontinued
zezwalaj NULL
na wartości), należy zachować szczególną ostrożność w obsłudze tych danych wejściowych skalarnych.
W szczególności parametr wejściowy musi być typu Object
, ponieważ wartość przychodząca może być wystąpieniem DBNull
zamiast oczekiwanego typu danych. Ponadto należy sprawdzić, czy wartość przychodząca jest wartością bazy danych NULL
. Oznacza to, że jeśli chcemy DisplayPrice
, aby metoda akceptowała cenę jako wartość skalarną, musimy użyć następującego kodu:
Protected Function DisplayPrice(ByVal unitPrice As Object) As String
' If price is less than $20.00, return the price, highlighted
If Not Convert.IsDBNull(unitPrice) AndAlso CType(unitPrice, Decimal) < 20 Then
Return String.Concat("<span class="AffordablePriceEmphasis">", _
CType(unitPrice, Decimal).ToString("C"), "</span>")
Else
' Otherwise return the text, "Please call for a price quote"
Return "<span>Please call for a price quote</span>"
End If
End Function
Należy pamiętać, że unitPrice
parametr wejściowy jest typu Object
i że instrukcja warunkowa została zmodyfikowana w celu ustalenia, czy jest, czy unitPrice
nie DBNull
. Ponadto, ponieważ unitPrice
parametr wejściowy jest przekazywany jako element , musi zostać rzutowany na wartość dziesiętną Object
.
Krok 2. Wywoływanie funkcji formatowania z elementu ItemTemplate elementu DataList
Dzięki funkcjom formatowania dodanym do naszej ASP.NET strony kod-za klasą, wszystko, co pozostaje, polega na wywołaniu tych funkcji formatowania z tabeli DataList s ItemTemplate
. Aby wywołać funkcję formatowania z szablonu, umieść wywołanie funkcji w składni powiązania danych:
<%# MethodName(inputParameter1, inputParameter2, ...) %>
W elemecie DataList kontrolka Sieć Web Etykieta ItemTemplate
ProductNameLabel
wyświetla obecnie nazwę produktu, przypisując jej Text
właściwość wynik .<%# Eval("ProductName") %>
Aby wyświetlić nazwę plus tekst [DISCONTINUED], w razie potrzeby zaktualizuj składnię deklaratywną, aby zamiast tego przypisywać Text
właściwość wartości DisplayProductNameAndDiscontinuedStatus
metody. W tym celu musimy przekazać nazwę produktu i wycofać wartości przy użyciu Eval("columnName")
składni. Eval
zwraca wartość typu Object
, ale DisplayProductNameAndDiscontinuedStatus
metoda oczekuje parametrów wejściowych typu String
i Boolean
dlatego musimy rzutować wartości zwracane przez Eval
metodę do oczekiwanych typów parametrów wejściowych, w następujący sposób:
<h4>
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# DisplayProductNameAndDiscontinuedStatus((string) Eval("ProductName"),
(bool) Eval("Discontinued")) %>'>
</asp:Label>
</h4>
Aby wyświetlić cenę, możemy po prostu ustawić UnitPriceLabel
właściwość Label Text
na wartość zwróconą przez DisplayPrice
metodę, podobnie jak w przypadku wyświetlania nazwy produktu i tekstu [DISCONTINUED]. Jednak zamiast przekazywać jako UnitPrice
parametr wejściowy skalarny, zamiast tego przekazujemy całe ProductsRow
wystąpienie:
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# DisplayPrice((Northwind.ProductsRow)
((System.Data.DataRowView) Container.DataItem).Row) %>'>
</asp:Label>
Po wywołaniu funkcji formatowania poświęć chwilę, aby wyświetlić postęp w przeglądarce. Ekran powinien wyglądać podobnie do rysunku 5, a wycofane produkty, w tym tekst [DISCONTINUED] i te produkty kosztują ponad 20,00 USD po ich cenie zastąpionej tekstem Proszę zadzwonić do oferty cenowej .
Rysunek 5. W przypadku drogich produktów cena jest zastępowana tekstem, wywołaj ofertę cenową (kliknij, aby wyświetlić obraz pełnowymiarowy)
Podsumowanie
Formatowanie zawartości kontrolki DataList lub Repeater na podstawie danych można wykonać przy użyciu dwóch technik. Pierwszą techniką jest utworzenie procedury obsługi zdarzeń dla ItemDataBound
zdarzenia, która jest uruchamiana jako każdy rekord w źródle danych jest powiązany z nowym DataListItem
lub RepeaterItem
. W procedurze ItemDataBound
obsługi zdarzeń można zbadać dane bieżącego elementu, a następnie można zastosować formatowanie do zawartości szablonu lub , dla s DataListItem
, do całego elementu.
Alternatywnie można zrealizować niestandardowe formatowanie za pomocą funkcji formatowania. Funkcja formatowania to metoda, którą można wywołać z szablonów DataList lub Repeater, które zwracają kod HTML do emitowania w jego miejscu. Często kod HTML zwracany przez funkcję formatowania jest określany przez wartości powiązane z bieżącym elementem. Te wartości można przekazać do funkcji formatowania jako wartości skalarne lub przekazując cały obiekt powiązany z elementem (na przykład ProductsRow
wystąpienie).
Szczęśliwe programowanie!
Informacje o autorze
Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.
Specjalne podziękowania
Ta seria samouczków została sprawdzona przez wielu pomocnych recenzentów. Recenzenci w tym samouczku to Yaakov Ellis, Randy Schmidt i Liz Shulok. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresem mitchell@4GuysFromRolla.com.