So I created a new ascx in the Templates/Categories folder and added the template, updated my categories to use the new template id and... it doesn't work with this error:
Parser Error Message: Could not load type 'NopSolutions.NopCommerce.Web.Templates.Categories.ProductsInLines3'.
Which, looking about suggests I need to recompile the site - which seems a bit much considering I just wanna adjust how category pages are displayed.
The site is already deployed and I don't want to muck up future upgrades I'm concerned that if I have to recompile the site now, in order to get my new template to work, that when 2.0 is released I'll have to remember to recompile against that version and forever more.
I have recompiled the site (downloaded the source) with my template and there are no errors - so I'm pretty confident my page works. But the live site was deployed using Microsoft Web Platform Installer and I really don't like the idea of redeploying the whole site just for a single template.
This is my aspx:
<%@ Control Language="C#" AutoEventWireup="true"
Inherits="NopSolutions.NopCommerce.Web.Templates.Categories.ProductsInLines3" CodeBehind="ProductsInLines3.ascx.cs" %>
<%@ Register TagPrefix="nopCommerce" TagName="PriceRangeFilter" Src="~/Modules/PriceRangeFilter.ascx" %>
<%@ Register TagPrefix="nopCommerce" TagName="ProductSpecificationFilter" Src="~/Modules/ProductSpecificationFilter.ascx" %>
<%@ Register TagPrefix="nopCommerce" TagName="ProductBox2" Src="~/Modules/ProductBox2.ascx" %>
<%@ Register TagPrefix="nopCommerce" TagName="ProductBox1" Src="~/Modules/ProductBox1.ascx" %>
<div class="category-page">
<div class="page-title">
<h1><asp:Literal runat="server" ID="lName"></asp:Literal></h1>
</div>
<div class="clear">
</div>
<div class="category-description">
<asp:Literal runat="server" ID="lDescription"></asp:Literal>
</div>
<div class="clear">
</div>
<div class="sub-category-list">
<asp:Repeater ID="rptrSubCategories" runat="server" OnItemDataBound="rptrSubCategories_ItemDataBound">
<ItemTemplate>
<asp:HyperLink ID="hlCategory" runat="server" Text='<%#Server.HtmlEncode(Eval("LocalizedName").ToString()) %>' />
</ItemTemplate>
<SeparatorTemplate>
<br />
</SeparatorTemplate>
</asp:Repeater>
</div>
<div class="clear">
</div>
<asp:Panel runat="server" ID="pnlSorting" CssClass="product-sorting">
<%=GetLocaleResourceString("ProductSorting.SortBy")%>
<asp:DropDownList ID="ddlSorting" runat="server" OnSelectedIndexChanged="ddlSorting_SelectedIndexChanged"
AutoPostBack="true" />
</asp:Panel>
<div class="clear">
</div>
<asp:Panel runat="server" ID="pnlFilters" CssClass="product-filters">
<div class="filter-title">
<asp:Label runat="server" ID="lblProductFilterTitle">
<%=GetLocaleResourceString("Products.FilterOptionsTitle")%>
</asp:Label>
</div>
<div class="filter-item">
<nopcommerce:pricerangefilter id="ctrlPriceRangeFilter" runat="server" />
</div>
<div class="filter-item">
<nopcommerce:productspecificationfilter id="ctrlProductSpecificationFilter" runat="server" />
</div>
</asp:Panel>
<div class="clear">
</div>
<div class="product-list1">
<asp:ListView ID="lvCatalog" runat="server">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
</LayoutTemplate>
<ItemTemplate>
<div class="item-box">
<nopcommerce:productbox2 id="ctrlProductBox" product='<%# Container.DataItem %>'
runat="server" />
</div>
</ItemTemplate>
</asp:ListView>
<div class="clear">
</div>
<div class="product-pager">
<nopcommerce:pager runat="server" id="catalogPager" firstbuttontext="<% $NopResources:Pager.First %>"
lastbuttontext="<% $NopResources:Pager.Last %>" nextbuttontext="<% $NopResources:Pager.Next %>"
previousbuttontext="<% $NopResources:Pager.Previous %>" currentpagetext="Pager.CurrentPage" />
</div>
</div>
</div>
and this is the code behind:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using NopSolutions.NopCommerce.BusinessLogic;
using NopSolutions.NopCommerce.BusinessLogic.Categories;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.Directory;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Localization;
using NopSolutions.NopCommerce.BusinessLogic.Media;
using NopSolutions.NopCommerce.BusinessLogic.Products;
using NopSolutions.NopCommerce.BusinessLogic.SEO;
using NopSolutions.NopCommerce.Common.Utils;
namespace NopSolutions.NopCommerce.Web.Templates.Categories
{
public partial class ProductsInLines3 : BaseNopFrontendUserControl
{
#region Protected Methods
protected void BindData()
{
var category = this.CategoryService.GetCategoryById(this.CategoryId);
lName.Text = Server.HtmlEncode(category.LocalizedName);
lDescription.Text = category.LocalizedDescription;
//subcategories
var subCategories = this.CategoryService.GetAllCategoriesByParentCategoryId(this.CategoryId);
if (subCategories.Count > 0)
{
rptrSubCategories.DataSource = subCategories;
rptrSubCategories.DataBind();
}
else
rptrSubCategories.Visible = false;
//price ranges
this.ctrlPriceRangeFilter.PriceRanges = category.PriceRanges;
//page size
int totalRecords = 0;
int pageSize = 10;
if (category.PageSize > 0)
{
pageSize = category.PageSize;
}
//price ranges
decimal? minPrice = null;
decimal? maxPrice = null;
decimal? minPriceConverted = null;
decimal? maxPriceConverted = null;
if (ctrlPriceRangeFilter.SelectedPriceRange != null)
{
minPrice = ctrlPriceRangeFilter.SelectedPriceRange.From;
if (minPrice.HasValue)
{
minPriceConverted = this.CurrencyService.ConvertCurrency(minPrice.Value, NopContext.Current.WorkingCurrency, this.CurrencyService.PrimaryStoreCurrency);
}
maxPrice = ctrlPriceRangeFilter.SelectedPriceRange.To;
if (maxPrice.HasValue)
{
maxPriceConverted = this.CurrencyService.ConvertCurrency(maxPrice.Value, NopContext.Current.WorkingCurrency, this.CurrencyService.PrimaryStoreCurrency);
}
}
//specification filter
var psoFilterOption = ctrlProductSpecificationFilter.GetAlreadyFilteredSpecOptionIds();
//sorting
ProductSortingEnum orderBy = ProductSortingEnum.Position;
if (this.SettingManager.GetSettingValueBoolean("Common.AllowProductSorting"))
{
CommonHelper.SelectListItem(this.ddlSorting, CommonHelper.QueryStringInt("orderby"));
orderBy = (ProductSortingEnum)Enum.ToObject(typeof(ProductSortingEnum), int.Parse(ddlSorting.SelectedItem.Value));
}
//featured products are not supported by this template
//that's hwhy we load all featured and non-featured products
var productCollection = this.ProductService.GetAllProducts(this.CategoryId,
0, 0, null, minPriceConverted, maxPriceConverted,
string.Empty, false, pageSize, this.CurrentPageIndex,
psoFilterOption, orderBy, out totalRecords);
if (productCollection.Count > 0)
{
this.catalogPager.PageSize = pageSize;
this.catalogPager.TotalRecords = totalRecords;
this.catalogPager.PageIndex = this.CurrentPageIndex;
this.lvCatalog.DataSource = productCollection;
this.lvCatalog.DataBind();
}
else
{
this.lvCatalog.Visible = false;
this.pnlSorting.Visible = false;
}
}
protected void ddlSorting_SelectedIndexChanged(object sender, EventArgs e)
{
string url = CommonHelper.GetThisPageUrl(true);
url = CommonHelper.ModifyQueryString(url, "orderby=" + ddlSorting.SelectedItem.Value, null);
Response.Redirect(url);
}
protected void dlSubCategories_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var category = e.Item.DataItem as Category;
string categoryURL = SEOHelper.GetCategoryUrl(category);
var hlImageLink = e.Item.FindControl("hlImageLink") as HyperLink;
if (hlImageLink != null)
{
hlImageLink.ImageUrl = this.PictureService.GetPictureUrl(category.PictureId, this.SettingManager.GetSettingValueInteger("Media.Category.ThumbnailImageSize", 125), true);
hlImageLink.NavigateUrl = categoryURL;
hlImageLink.ToolTip = String.Format(GetLocaleResourceString("Media.Category.ImageLinkTitleFormat"), category.LocalizedName);
hlImageLink.Text = String.Format(GetLocaleResourceString("Media.Category.ImageAlternateTextFormat"), category.LocalizedName);
}
var hlCategory = e.Item.FindControl("hlCategory") as HyperLink;
if (hlCategory != null)
{
hlCategory.NavigateUrl = categoryURL;
hlCategory.ToolTip = String.Format(GetLocaleResourceString("Media.Category.ImageLinkTitleFormat"), category.LocalizedName);
hlCategory.Text = Server.HtmlEncode(category.LocalizedName);
}
}
}
protected void FillDropDowns()
{
if (this.SettingManager.GetSettingValueBoolean("Common.AllowProductSorting"))
{
ddlSorting.Items.Clear();
var ddlSortPositionItem = new ListItem(GetLocaleResourceString("ProductSorting.Position"), ((int)ProductSortingEnum.Position).ToString());
ddlSorting.Items.Add(ddlSortPositionItem);
var ddlSortNameItem = new ListItem(GetLocaleResourceString("ProductSorting.Name"), ((int)ProductSortingEnum.Name).ToString());
ddlSorting.Items.Add(ddlSortNameItem);
var ddlSortPriceItem = new ListItem(GetLocaleResourceString("ProductSorting.Price"), ((int)ProductSortingEnum.Price).ToString());
ddlSorting.Items.Add(ddlSortPriceItem);
}
else
{
pnlSorting.Visible = false;
}
}
protected void lvCatalog_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var dataItem = e.Item as ListViewDataItem;
if (dataItem != null)
{
var product = dataItem.DataItem as Product;
if (product != null)
{
var hlProduct = dataItem.FindControl("hlProduct") as HyperLink;
hlProduct.NavigateUrl = SEOHelper.GetProductUrl(product);
}
}
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
ctrlPriceRangeFilter.ExcludedQueryStringParams = catalogPager.QueryStringProperty;
ctrlProductSpecificationFilter.ExcludedQueryStringParams = catalogPager.QueryStringProperty;
ctrlProductSpecificationFilter.CategoryId = this.CategoryId;
ctrlProductSpecificationFilter.ReservedQueryStringParams = "CategoryId,";
ctrlProductSpecificationFilter.ReservedQueryStringParams += "orderby,";
ctrlProductSpecificationFilter.ReservedQueryStringParams += ctrlPriceRangeFilter.QueryStringProperty;
ctrlProductSpecificationFilter.ReservedQueryStringParams += ",";
ctrlProductSpecificationFilter.ReservedQueryStringParams += catalogPager.QueryStringProperty;
}
protected override void OnPreRender(EventArgs e)
{
this.pnlFilters.Visible = ctrlPriceRangeFilter.Visible || ctrlProductSpecificationFilter.Visible;
base.OnPreRender(e);
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
FillDropDowns();
BindData();
}
}
protected void rptrSubCategories_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
var category = e.Item.DataItem as Category;
var hlCategory = e.Item.FindControl("hlCategory") as HyperLink;
if (hlCategory != null)
{
hlCategory.NavigateUrl = SEOHelper.GetCategoryUrl(category);
}
}
}
#endregion
}
}