Partie 7 : Ajout de fonctionnalités
par Joe Stagner
Tailspin Spyworks montre à quel point il est extrêmement simple de créer des applications puissantes et évolutives pour la plateforme .NET. Il montre comment utiliser les nouvelles fonctionnalités de ASP.NET 4 pour créer un magasin en ligne, y compris les achats, les caisses et l’administration.
Cette série de tutoriels détaille toutes les étapes à suivre pour générer l’exemple d’application Tailspin Spyworks. La partie 7 ajoute des fonctionnalités supplémentaires, telles que la révision de compte, les révisions de produits et les contrôles utilisateur « articles populaires » et « également achetés ».
Ajout de fonctionnalités
Bien que les utilisateurs puissent parcourir notre catalogue, placer des articles dans leur panier d’achat et effectuer le processus de paiement, il existe un certain nombre de fonctionnalités de prise en charge que nous allons inclure pour améliorer notre site.
- Révision de compte (répertorier les commandes passées et afficher les détails.)
- Ajoutez du contenu spécifique au contexte à la page d’accueil.
- Ajoutez une fonctionnalité pour permettre aux utilisateurs de passer en revue les produits du catalogue.
- Créez un contrôle utilisateur pour afficher les éléments populaires et placez ce contrôle sur la première page.
- Créez un contrôle utilisateur « Également acheté » et ajoutez-le à la page des détails du produit.
- Ajouter une page contact.
- Ajoutez une page À propos de.
- Erreur globale
Examen de compte
Dans le dossier « Account », créez deux pages .aspx, l’une nommée OrderList.aspx et l’autre nommée OrderDetails.aspx.
OrderList.aspx tire parti des contrôles GridView et EntityDataSource comme nous l’avons fait précédemment.
<div class="ContentHead">Order History</div><br />
<asp:GridView ID="GridView_OrderList" runat="server" AllowPaging="True"
ForeColor="#333333" GridLines="None" CellPadding="4" Width="100%"
AutoGenerateColumns="False" DataKeyNames="OrderID"
DataSourceID="EDS_Orders" AllowSorting="True" ViewStateMode="Disabled" >
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:BoundField DataField="OrderID" HeaderText="OrderID" ReadOnly="True"
SortExpression="OrderID" />
<asp:BoundField DataField="CustomerName" HeaderText="Customer"
SortExpression="CustomerName" />
<asp:BoundField DataField="OrderDate" HeaderText="Order Date"
SortExpression="OrderDate" />
<asp:BoundField DataField="ShipDate" HeaderText="Ship Date"
SortExpression="ShipDate" />
<asp:HyperLinkField HeaderText="Show Details" Text="Show Details"
DataNavigateUrlFields="OrderID"
DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}" />
</Columns>
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
<SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" />
<SortedAscendingCellStyle BackColor="#FDF5AC" />
<SortedAscendingHeaderStyle BackColor="#4D0000" />
<SortedDescendingCellStyle BackColor="#FCF6C0" />
<SortedDescendingHeaderStyle BackColor="#820000" />
<SortedAscendingCellStyle BackColor="#FDF5AC"></SortedAscendingCellStyle>
<SortedAscendingHeaderStyle BackColor="#4D0000"></SortedAscendingHeaderStyle>
<SortedDescendingCellStyle BackColor="#FCF6C0"></SortedDescendingCellStyle>
<SortedDescendingHeaderStyle BackColor="#820000"></SortedDescendingHeaderStyle>
</asp:GridView>
<asp:EntityDataSource ID="EDS_Orders" runat="server" EnableFlattening="False"
AutoGenerateWhereClause="True"
Where=""
OrderBy="it.OrderDate DESC"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Orders" >
<WhereParameters>
<asp:SessionParameter Name="CustomerName" SessionField="UserName" />
</WhereParameters>
</asp:EntityDataSource>
EntityDataSource sélectionne les enregistrements de la table Orders filtrés sur le UserName (voir WhereParameter) que nous définissons dans une variable de session lorsque l’utilisateur se connecte.
Notez également ces paramètres dans le champ HyperlinkField du GridView :
DataNavigateUrlFields="OrderID" DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}"
Celles-ci spécifient le lien vers l’affichage Détails de la commande pour chaque produit en spécifiant le champ OrderID en tant que paramètre QueryString vers la page OrderDetails.aspx.
OrderDetails.aspx
Nous allons utiliser un contrôle EntityDataSource pour accéder aux commandes et à un Contrôle FormView pour afficher les données Order, ainsi qu’un autre EntityDataSource avec un GridView pour afficher tous les éléments de ligne de l’ordre.
<asp:FormView ID="FormView1" runat="server" CellPadding="4"
DataKeyNames="OrderID"
DataSourceID="EDS_Order" ForeColor="#333333" Width="250px">
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<ItemTemplate>
OrderID : <%# Eval("OrderID") %><br />
CustomerName : <%# Eval("CustomerName") %><br />
Order Date : <%# Eval("OrderDate") %><br />
Ship Date : <%# Eval("ShipDate") %><br />
</ItemTemplate>
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
</asp:FormView>
<asp:EntityDataSource ID="EDS_Order" runat="server" EnableFlattening="False"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Orders"
AutoGenerateWhereClause="True"
Where=""
EntityTypeFilter="" Select="">
<WhereParameters>
<asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
<asp:GridView ID="GridView_OrderDetails" runat="server"
AutoGenerateColumns="False"
DataKeyNames="ProductID,UnitCost,Quantity"
DataSourceID="EDS_OrderDetails"
CellPadding="4" GridLines="Vertical" CssClass="CartListItem"
onrowdatabound="MyList_RowDataBound" ShowFooter="True"
ViewStateMode="Disabled">
<AlternatingRowStyle CssClass="CartListItemAlt" />
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="Product ID" ReadOnly="True"
SortExpression="ProductID" />
<asp:BoundField DataField="ModelNumber" HeaderText="Model Number"
SortExpression="ModelNumber" />
<asp:BoundField DataField="ModelName" HeaderText="Model Name"
SortExpression="ModelName" />
<asp:BoundField DataField="UnitCost" HeaderText="Unit Cost" ReadOnly="True"
SortExpression="UnitCost" DataFormatString="{0:c}" />
<asp:BoundField DataField="Quantity" HeaderText="Quantity" ReadOnly="True"
SortExpression="Quantity" />
<asp:TemplateField>
<HeaderTemplate>Item Total</HeaderTemplate>
<ItemTemplate>
<%# (Convert.ToDouble(Eval("Quantity")) * Convert.ToDouble(Eval("UnitCost")))%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle CssClass="CartListFooter"/>
<HeaderStyle CssClass="CartListHead" />
</asp:GridView>
<asp:EntityDataSource ID="EDS_OrderDetails" runat="server"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EnableFlattening="False"
EntitySetName="VewOrderDetails"
AutoGenerateWhereClause="True"
Where="">
<WhereParameters>
<asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
Dans le fichier Code Behind (OrderDetails.aspx.cs), nous avons deux petits éléments de nettoyage.
Tout d’abord, nous devons nous assurer que OrderDetails obtient toujours un OrderId.
protected void Page_Load(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(Request.QueryString["OrderId"]))
{
Response.Redirect("~/Account/OrderList.aspx");
}
}
Nous devons également calculer et afficher le total des commandes à partir des éléments de ligne.
decimal _CartTotal = 0;
protected void MyList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TailspinSpyworks.Data_Access.VewOrderDetail myCart = new
Data_Access.VewOrderDetail();
myCart = (TailspinSpyworks.Data_Access.VewOrderDetail)e.Row.DataItem;
_CartTotal += Convert.ToDecimal(myCart.UnitCost * myCart.Quantity);
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[5].Text = "Total: " + _CartTotal.ToString("C");
}
}
Page d’accueil
Ajoutons du contenu statique à la page Default.aspx.
Tout d’abord, je vais créer un dossier « Contenu » et dans celui-ci un dossier Images (et j’inclurai une image à utiliser sur la page d’accueil.)
Dans l’espace réservé inférieur de la page Default.aspx, ajoutez le balisage suivant.
<h2>
<asp:LoginView ID="LoginView_VisitorGreeting" runat="server">
<AnonymousTemplate>
Welcome to the Store !
</AnonymousTemplate>
<LoggedInTemplate>
Hi <asp:LoginName ID="LoginName_Welcome" runat="server" />. Thanks for coming back.
</LoggedInTemplate>
</asp:LoginView>
</h2>
<p><strong>TailSpin Spyworks</strong> demonstrates how extraordinarily simple it is to create powerful, scalable applications for the .NET platform. </p>
<table>
<tr>
<td>
<h3>Some Implementation Features.</h3>
<ul>
<li><a href="#">CSS Based Design.</a></li>
<li><a href="#">Data Access via Linq to Entities.</a></li>
<li><a href="#">MasterPage driven design.</a></li>
<li><a href="#">Modern ASP.NET Controls User.</a></li>
<li><a href="#">Integrated Ajac Control Toolkit Editor.</a></li>
</ul>
</td>
<td>
<img src="Content/Images/SampleProductImage.gif" alt=""/>
</td>
</tr>
</table>
<table>
<tr>
<td colspan="2"><hr /></td>
</tr>
<tr>
<td>
<!-- Popular Items -->
</td>
<td>
<center><h3>Ecommerce the .NET 4 Way</h3></center>
<blockquote>
<p>
ASP.NET offers web developers the benefit of more that a decade of innovation.
This demo leverages many of the latest features of ASP.NET development to
illustrate really simply building rich web applications with ASP.NET can be.
For more information about build web applications with ASP.NET please visit the
community web site at www.asp.net
</p>
</blockquote>
</td>
</tr>
</table>
<h3>Spyworks Event Calendar</h3>
<table>
<tr class="rowH">
<th>Date</th>
<th>Title</th>
<th>Description</th>
</tr>
<tr class="rowA">
<td>June 01, 2011</td>
<td>Sed vestibulum blandit</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowB">
<td>November 28, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowA">
<td>November 23, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowB">
<td>November 21, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
</table>
Avis sur les produits
Tout d’abord, nous allons ajouter un bouton avec un lien vers un formulaire que nous pouvons utiliser pour entrer une révision de produit.
<div class="SubContentHead">Reviews</div><br />
<a id="ReviewList_AddReview" href="ReviewAdd.aspx?productID=<%# Eval("ProductID") %>">
<img id="Img2" runat="server"
src="~/Styles/Images/review_this_product.gif" alt="" />
</a>
Notez que nous transmettons le ProductID dans la chaîne de requête
Nous allons maintenant ajouter la page nommée ReviewAdd.aspx
Cette page utilise le ASP.NET Ajax Control Toolkit. Si vous ne l’avez pas déjà fait, vous pouvez le télécharger à partir de DevExpress et vous trouverez des conseils sur la configuration du kit de ressources pour une utilisation avec Visual Studio ici https://www.asp.net/learn/ajax-videos/video-76.aspx.
En mode création, faites glisser les contrôles et les validateurs à partir de la boîte à outils et créez un formulaire comme celui ci-dessous.
Le balisage ressemblera à ceci.
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
<div class="ContentHead">Add Review - <asp:label id="ModelName" runat="server" /></div>
<div>
<span class="NormalBold">Name</span><br />
<asp:TextBox id="Name" runat="server" Width="400px" /><br />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator1"
ControlToValidate="Name"
Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="'Name' must not be left blank." /><br />
<span class="NormalBold">Email</span><br />
<asp:TextBox id="Email" runat="server" Width="400px" /><br />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator2"
ControlToValidate="Email" Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="'Email' must not be left blank." />
<br /><hr /><br />
<span class="NormalBold">Rating</span><br /><br />
<asp:RadioButtonList ID="Rating" runat="server">
<asp:ListItem value="5" selected="True"
Text='<img src="Styles/Images/reviewrating5.gif" alt=""> (Five Stars) ' />
<asp:ListItem value="4" selected="True"
Text='<img src="Styles/Images/reviewrating4.gif" alt=""> (Four Stars) ' />
<asp:ListItem value="3" selected="True"
Text='<img src="Styles/Images/reviewrating3.gif" alt=""> (Three Stars) ' />
<asp:ListItem value="2" selected="True"
Text='<img src="Styles/Images/reviewrating2.gif" alt=""> (Two Stars) ' />
<asp:ListItem value="1" selected="True"
Text='<img src="Styles/Images/reviewrating1.gif" alt=""> (One Stars) ' />
</asp:RadioButtonList>
<br /><hr /><br />
<span class="NormalBold">Comments</span><br />
<cc1:Editor ID="UserComment" runat="server" />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator3"
ControlToValidate="UserComment" Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="Please enter your comment." /><br /><br />
<asp:ImageButton ImageURL="Styles/Images/submit.gif" runat="server"
id="ReviewAddBtn" onclick="ReviewAddBtn_Click" />
<br /><br /><br />
</div>
Maintenant que nous pouvons entrer des avis, affichons ces avis sur la page du produit.
Ajoutez ce balisage à la page ProductDetails.aspx.
<asp:ListView ID="ListView_Comments" runat="server"
DataKeyNames="ReviewID,ProductID,Rating" DataSourceID="EDS_CommentsList">
<ItemTemplate>
<tr>
<td><%# Eval("CustomerName") %></td>
<td>
<img src='Styles/Images/ReviewRating_d<%# Eval("Rating") %>.gif' alt="">
<br />
</td>
<td>
<%# Eval("Comments") %>
</td>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr>
<td><%# Eval("CustomerName") %></td>
<td>
<img src='Styles/Images/ReviewRating_da<%# Eval("Rating") %>.gif' alt="">
<br />
</td>
<td><%# Eval("Comments") %></td>
</tr>
</AlternatingItemTemplate>
<EmptyDataTemplate>
<table runat="server">
<tr><td>There are no reviews yet for this product.</td></tr>
</table>
</EmptyDataTemplate>
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table ID="itemPlaceholderContainer" runat="server" border="1">
<tr runat="server">
<th runat="server">Customer</th>
<th runat="server">Rating</th>
<th runat="server">Comments</th>
</tr>
<tr ID="itemPlaceholder" runat="server"></tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server">
<asp:DataPager ID="DataPager1" runat="server">
<Fields>
<asp:NextPreviousPagerField ButtonType="Button"
ShowFirstPageButton="True"
ShowLastPageButton="True" />
</Fields>
</asp:DataPager>
</td>
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
<asp:EntityDataSource ID="EDS_CommentsList" runat="server" EnableFlattening="False"
AutoGenerateWhereClause="True"
EntityTypeFilter=""
Select="" Where=""
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Reviews">
<WhereParameters>
<asp:QueryStringParameter Name="ProductID" QueryStringField="productID"
Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
L’exécution de notre application maintenant et la navigation vers un produit affiche les informations sur le produit, y compris les avis des clients.
Contrôle Éléments populaires (création de contrôles utilisateur)
Afin d’augmenter les ventes sur votre site web, nous allons ajouter quelques fonctionnalités à la « vente suggestive » produits populaires ou connexes.
La première de ces fonctionnalités sera une liste des produits les plus populaires dans notre catalogue de produits.
Nous allons créer un « contrôle utilisateur » pour afficher les articles les plus vendus sur la page d’accueil de notre application. Étant donné qu’il s’agit d’un contrôle, nous pouvons l’utiliser sur n’importe quelle page en le faisant simplement glisser-déposer dans le concepteur de Visual Studio sur n’importe quelle page de notre choix.
Dans l’Explorateur de solutions de Visual Studio, cliquez avec le bouton droit sur le nom de la solution et créez un répertoire nommé « Controls ». Bien qu’il ne soit pas nécessaire de le faire, nous allons aider à maintenir l’organisation de notre projet en créant tous nos contrôles utilisateur dans le répertoire « Controls ».
Cliquez avec le bouton droit sur le dossier controls et choisissez « Nouvel élément » :
Spécifiez un nom pour notre contrôle « PopularItems ». Notez que l’extension de fichier pour les contrôles utilisateur est .ascx et non .aspx.
Notre contrôle Utilisateur d’éléments populaires sera défini comme suit.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
<div class="MostPopularHead">Our most popular items this week</div>
<div id="PanelPopularItems" runat="server">
<asp:Repeater ID="RepeaterItemsList" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<a class='MostPopularItemText'
href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'>
<%# Eval("ModelName") %></a><br />
</ItemTemplate>
<FooterTemplate></FooterTemplate>
</asp:Repeater>
</div>
Ici, nous utilisons une méthode que nous n’avons pas encore utilisée dans cette application. Nous utilisons le contrôle repeater et, au lieu d’utiliser un contrôle de source de données, nous lisons le contrôle Repeater aux résultats d’une requête LINQ to Entities.
Dans le code derrière notre contrôle, nous procédons comme suit.
using TailspinSpyworks.Data_Access;
protected void Page_Load(object sender, EventArgs e)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending select orderdgrp).Take(5);
RepeaterItemsList.DataSource = query;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Load Popular Items - " +
exp.Message.ToString(), exp);
}
}
}
Notez également cette ligne importante en haut du balisage de notre contrôle.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
Étant donné que les éléments les plus populaires ne seront pas modifiés d’une minute à l’autre, nous pouvons ajouter une directive de mal pour améliorer les performances de notre application. Cette directive entraîne l’exécution du code des contrôles uniquement lorsque la sortie mise en cache du contrôle expire. Sinon, la version mise en cache de la sortie du contrôle sera utilisée.
Il ne nous reste plus qu’à inclure notre nouveau contrôle dans notre page Default.aspx.
Utilisez le glisser-déplacer pour placer une instance du contrôle dans la colonne ouverte de notre formulaire par défaut.
Maintenant, lorsque nous exécutons notre application, la page d’accueil affiche les éléments les plus populaires.
Contrôle « Également acheté » (contrôles utilisateur avec des paramètres)
Le deuxième contrôle utilisateur que nous allons créer passera la vente suggestive au niveau suivant en ajoutant la spécificité du contexte.
La logique de calcul des principaux articles « également achetés » n’est pas triviale.
Notre contrôle « Également acheté » sélectionne les enregistrements OrderDetails (précédemment achetés) pour le ProductID actuellement sélectionné et récupère les OrderID pour chaque commande unique trouvée.
Ensuite, nous allons sélectionner les produits de toutes ces commandes et additionner les quantités achetées. Nous allons trier les produits en fonction de cette somme de quantité et afficher les cinq premiers éléments.
Étant donné la complexité de cette logique, nous allons implémenter cet algorithme en tant que procédure stockée.
Le T-SQL de la procédure stockée est le suivant.
ALTER PROCEDURE dbo.SelectPurchasedWithProducts
@ProductID int
AS
SELECT TOP 5
OrderDetails.ProductID,
Products.ModelName,
SUM(OrderDetails.Quantity) as TotalNum
FROM
OrderDetails
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID
WHERE OrderID IN
(
/* This inner query should retrieve all orders that have contained the productID */
SELECT DISTINCT OrderID
FROM OrderDetails
WHERE ProductID = @ProductID
)
AND OrderDetails.ProductID != @ProductID
GROUP BY OrderDetails.ProductID, Products.ModelName
ORDER BY TotalNum DESC
RETURN
Notez que cette procédure stockée (SelectPurchasedWithProducts) existait dans la base de données lorsque nous l’avons incluse dans notre application et lorsque nous avons généré le modèle de données d’entité, nous avons spécifié que, en plus des tables et vues dont nous avions besoin, le modèle de données d’entité doit inclure cette procédure stockée.
Pour accéder à la procédure stockée à partir d’Entity Data Model, nous devons importer la fonction.
Double-cliquez sur le modèle de données d’entité dans l’Explorer Solutions pour l’ouvrir dans le concepteur et ouvrir l’Explorateur de modèles, puis cliquez avec le bouton droit dans le concepteur et sélectionnez « Ajouter une importation de fonction ».
Cette opération ouvre cette boîte de dialogue.
Renseignez les champs comme vous le voyez ci-dessus, en sélectionnant « SelectPurchasedWithProducts » et utilisez le nom de la procédure pour le nom de notre fonction importée.
Cliquez sur « OK ».
Après avoir effectué cette opération, nous pouvons simplement programmer par rapport à la procédure stockée comme tout autre élément du modèle.
Ainsi, dans notre dossier « Contrôles », créez un contrôle utilisateur nommé AlsoPurchased.ascx.
Le balisage de ce contrôle semblera très familier au contrôle PopularItems.
<div>
<div class="MostPopularHead">
<asp:Label ID="LabelTitle" runat="server" Text=" Customers who bought this also bought:"></asp:Label></div>
<div id="PanelAlsoBoughtItems" runat="server">
<asp:Repeater ID="RepeaterItemsList" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<a class='MostPopularItemText' href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'><%# Eval("ModelName") %></a><br />
</ItemTemplate>
<FooterTemplate></FooterTemplate>
</asp:Repeater>
</div>
</div>
La différence notable est que ne mettez pas en cache la sortie, car les éléments à rendre diffèrent selon le produit.
Le ProductId est une « propriété » pour le contrôle.
private int _ProductId;
public int ProductId
{
get { return _ProductId ; }
set { _ProductId = Convert.ToInt32(value); }
}
Dans le gestionnaire d’événements PreRender du contrôle, nous avons décidé d’effectuer trois opérations.
- Vérifiez que productID est défini.
- Vérifiez s’il existe des produits qui ont été achetés avec le produit actuel.
- Sortie de certains éléments comme déterminé dans #2.
Notez qu’il est facile d’appeler la procédure stockée via le modèle.
//--------------------------------------------------------------------------------------+
protected void Page_PreRender(object sender, EventArgs e)
{
if (_ProductId < 1)
{
// This should never happen but we could expand the use of this control by reducing
// the dependency on the query string by selecting a few RANDOME products here.
Debug.Fail("ERROR : The Also Purchased Control Can not be used without
setting the ProductId.");
throw new Exception("ERROR : It is illegal to load the AlsoPurchased COntrol
without setting a ProductId.");
}
int ProductCount = 0;
using (CommerceEntities db = new CommerceEntities())
{
try
{
var v = db.SelectPurchasedWithProducts(_ProductId);
ProductCount = v.Count();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Retrieve Also Purchased Items - " +
exp.Message.ToString(), exp);
}
}
if (ProductCount > 0)
{
WriteAlsoPurchased(_ProductId);
}
else
{
WritePopularItems();
}
}
Après avoir déterminé qu’il y a « également acheté », nous pouvons simplement lier le répéteur aux résultats retournés par la requête.
//-------------------------------------------------------------------------------------+
private void WriteAlsoPurchased(int currentProduct)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var v = db.SelectPurchasedWithProducts(currentProduct);
RepeaterItemsList.DataSource = v;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Write Also Purchased - " +
exp.Message.ToString(), exp);
}
}
}
S’il n’y avait pas d’articles « également achetés », nous afficherons simplement d’autres articles populaires de notre catalogue.
//--------------------------------------------------------------------------------------+
private void WritePopularItems()
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp
where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending
select orderdgrp).Take(5);
LabelTitle.Text = "Other items you might be interested in: ";
RepeaterItemsList.DataSource = query;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Load Popular Items - " +
exp.Message.ToString(), exp);
}
}
}
Pour afficher les éléments « Également achetés », ouvrez la page ProductDetails.aspx et faites glisser le contrôle AlsoPurchased du Explorer Solutions afin qu’il apparaisse à cette position dans le balisage.
<table border="0">
<tr>
<td>
<img src='Catalog/Images/<%# Eval("ProductImage") %>' border="0"
alt='<%# Eval("ModelName") %>' />
</td>
<td><%# Eval("Description") %><br /><br /><br />
<uc1:AlsoPurchased ID="AlsoPurchased1" runat="server" />
</td>
</tr>
</table>
Cela crée une référence au contrôle en haut de la page ProductDetails.
<%@ Register src="Controls/AlsoPurchased.ascx" tagname="AlsoPurchased" tagprefix="uc1" %>
Étant donné que le contrôle utilisateur AlsoPurchased nécessite un numéro ProductId, nous allons définir la propriété ProductID de notre contrôle à l’aide d’une instruction Eval par rapport à l’élément de modèle de données actuel de la page.
Lorsque nous créons et exécutons maintenant et accédons à un produit, nous voyons les articles « Également achetés ».