Page 1 of 1

Controlling Popular Products

Posted: Mon Sep 16, 2013 7:32 pm
by Brewhaus
In our AC7 installation we have the Popular Products set up to show 'x' number of items (we have it set to three) out of the top 20 items. I have tried to get the Gold version to do the same, but when we change

IList<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);

to the same as in our AC7 file (20, 7) we show the top 20 items from category 7. This seems to override

private int _MaxItems = 3;

How can we set the file up to show only three items, but pulled from the top 20 sellers?

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 12:19 pm
by jguengerich
After you get the list of 20, you could use .Net's Radom class methods to get 3 (different) random numbers between 0 and 19. Then build a smaller list with the items in those 3 positions of the original list.

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 2:56 pm
by Brewhaus
It sounds like it is much more involved than the AC7 version. Is there that much of a change in the PopularProducts file?

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 2:57 pm
by jguengerich
I don't know, I never had AC7. There might be a simpler way to accomplish what you want, my post was just the first thing I thought of.

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 6:30 pm
by Brewhaus
In AC7 we just change this

Code: Select all

        int prefferedCategoryId = PageHelper.GetCategoryId();
        List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
        if (products != null && products.Count > 0)
to

Code: Select all

        int prefferedCategoryId = PageHelper.GetCategoryId();
        //List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
        List<Product> products = ProductDataSource.GetPopularProducts(20, 7);
        List<Product> randomProducts = new List<Product>();
        Random random = new Random();
        int count = 0;
        if (products.Count > 0)
I tried this in Gold and got an error page. :-(

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 6:47 pm
by jguengerich
I think if you look at your AC7 code and compare it to the AC Gold code more carefully, you'll find there are more lines you need to copy/change in AC Gold. What you show above is the start of what I suggested, but there has to be more code to finish the process.

Re: Controlling Popular Products

Posted: Tue Sep 17, 2013 7:10 pm
by Brewhaus
You are correct- I missed copying and pasting part of the code. It is below.

Code: Select all

        int prefferedCategoryId = PageHelper.GetCategoryId();
        //List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
        List<Product> products = ProductDataSource.GetPopularProducts(20, 7);
        List<Product> randomProducts = new List<Product>();
        Random random = new Random();
        int count = 0;
        if (products.Count > 0)
        {
            if (MaxItems > products.Count)
                MaxItems = products.Count;
            while (count < MaxItems)
            {
                int index = random.Next(0, products.Count);
                Product product = products[index];
                if (!randomProducts.Contains(product))
                {
                    randomProducts.Add(product);
                    count++;
                }
            }
        }
        products = randomProducts;
I have just not been able to figure out how to make this work with Gold. I keep coming up with errors. Am I overlooking something obvious?

Re: Controlling Popular Products

Posted: Wed Sep 18, 2013 6:42 am
by jguengerich
What error(s) are you getting? Also, since it isn't very long, a copy of the entire .cs file would make it easier to spot a problem.

Re: Controlling Popular Products

Posted: Wed Sep 18, 2013 7:58 am
by Brewhaus
If I recall, the error that we get has something to do with the products.count reference. I had to change back to the original file in order to continue working on the site development.

Here is the AC7 file

Code: Select all

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using CommerceBuilder.Common;
using CommerceBuilder.DigitalDelivery;
using CommerceBuilder.Products;
using CommerceBuilder.Orders;
using CommerceBuilder.Utility;

public partial class Webparts_PopularProductsDialog : System.Web.UI.UserControl
{
    private string _Caption = "Top Sellers";
    private int _MaxItems = 3;
    private string _Orientation = "HORIZONTAL";
    private int _Columns = 3;
    private string _ThumbnailPosition = "TOP"; // LEFT OR TOP

    /// <summary>
    /// Default is "TOP" , can be "TOP" or "LEFT"
    /// </summary>
    [Personalizable(), WebBrowsable()]
    public string ThumbnailPosition
    {
        get { return _ThumbnailPosition; }
        set { 
            _ThumbnailPosition = value;
            _ThumbnailPosition = value.ToUpperInvariant();
            if ((_ThumbnailPosition != "TOP") && (_ThumbnailPosition != "LEFT")) _ThumbnailPosition = "TOP";            

        }
    }

    /// <summary>
    /// Default is 3 columns, Only for HORIZONTAL Orientation
    /// </summary>
    [Personalizable(), WebBrowsable()]
    public int Columns
    {
        get { return _Columns; }
        set { 
            _Columns = value;
            if (Orientation == "HORIZONTAL") ProductList.RepeatColumns = Columns;
        }
    }
    

    [Personalizable(), WebBrowsable()]
    public string Orientation
    {
        get
        {
            return _Orientation;
        }
        set
        {
            _Orientation = value.ToUpperInvariant();
            if ((_Orientation != "HORIZONTAL") && (_Orientation != "VERTICAL")) _Orientation = "HORIZONTAL";
            if (_Orientation == "HORIZONTAL")
            {
                ProductList.RepeatColumns = Columns;
                ProductList.RepeatDirection = RepeatDirection.Horizontal;        
                ProductList.ItemStyle.CssClass = "rowSeparator";
                ProductList.AlternatingItemStyle.CssClass = "";
                
            }else{
                ProductList.RepeatColumns = 1;
                ProductList.RepeatDirection = RepeatDirection.Vertical;

                // THERE SHOULD BE DIFFERENT CSS STYLE FOR ALTERNATE ITEMS
                ProductList.ItemStyle.CssClass = "ProductItemView";
                ProductList.AlternatingItemStyle.CssClass = "ProductItemViewOdd";
            }
        }
    }

    [Personalizable(), WebBrowsable()]
    public string Caption
    {
        get { return _Caption; }
        set { _Caption = value; }
    }

    [Personalizable(), WebBrowsable()]
    public int MaxItems
    {
        get { return _MaxItems; }
        set { _MaxItems = value; }
    }

    protected void ProductList_ItemDataBound(object sender, DataListItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
        {
            Product product = (Product)e.Item.DataItem;
            Image thumbnail = PageHelper.RecursiveFindControl(e.Item, "Thumbnail") as Image;
            if (thumbnail != null)
            {
                if (!string.IsNullOrEmpty(product.ThumbnailUrl))
                {
                    thumbnail.ImageUrl = product.ThumbnailUrl;
                    thumbnail.Attributes.Add("hspace", "2");
                    thumbnail.Attributes.Add("vspace", "2");
                }
                else
                {
                    thumbnail.Visible = false;
                }
            }
            
            if (ThumbnailPosition == "LEFT")
            {
                Literal SingleRowLiteral = PageHelper.RecursiveFindControl(e.Item, "SingleRowLiteral") as Literal;
                Literal TwoRowsLiteral = PageHelper.RecursiveFindControl(e.Item, "TwoRowsLiteral") as Literal;

                if (SingleRowLiteral != null && TwoRowsLiteral != null)
                {
                    SingleRowLiteral.Visible = true;
                    TwoRowsLiteral.Visible = false;
                }                
            }
        }
    }

    protected void ProductList_ItemCommand(object source, DataListCommandEventArgs e)
    {
        if (e.CommandName == "AddToCart")
        {
            int productId = AlwaysConvert.ToInt(e.CommandArgument);
            BasketItem basketItem = BasketItemDataSource.CreateForProduct(productId, 1);
            if (basketItem != null)
            {
                // DETERMINE IF THE LICENSE AGREEMENT MUST BE REQUESTED
                BasketItemLicenseAgreementCollection basketItemLicenseAgreements = new BasketItemLicenseAgreementCollection(basketItem, LicenseAgreementMode.OnAddToBasket);
                if ((basketItemLicenseAgreements.Count > 0))
                {
                    // THESE AGREEMENTS MUST BE ACCEPTED TO ADD TO CART
                    List<BasketItem> basketItems = new List<BasketItem>();
                    basketItems.Add(basketItem);
                    string guidKey = Guid.NewGuid().ToString("N");
                    Cache.Add(guidKey, basketItems, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), System.Web.Caching.CacheItemPriority.NotRemovable, null);
                    string acceptUrl = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("~/Basket.aspx"));
                    string declineUrl = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Request.Url.ToString()));
                    Response.Redirect("~/BuyWithAgreement.aspx?Items=" + guidKey + "&AcceptUrl=" + acceptUrl + "&DeclineUrl=" + declineUrl);
                }
                Basket basket = Token.Instance.User.Basket;
                basket.Items.Add(basketItem);
                basket.Save();
                basket.Package();
                basket.Combine();
                Response.Redirect("~/Basket.aspx");
            }
        }
    }

    protected bool ShowAddToCart(object dataItem)
    {
        Product product = (Product)dataItem;
        return ((product.ProductOptions.Count == 0) && (product.KitStatus != KitStatus.Master));
    }

    protected void Page_PreRender(object sender, EventArgs e)
    {
        int prefferedCategoryId = PageHelper.GetCategoryId();
        //List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
        List<Product> products = ProductDataSource.GetPopularProducts(20, 7);
        List<Product> randomProducts = new List<Product>();
        Random random = new Random();
        int count = 0;
        if (products.Count > 0)
        {
            if (MaxItems > products.Count)
                MaxItems = products.Count;
            while (count < MaxItems)
            {
                int index = random.Next(0, products.Count);
                Product product = products[index];
                if (!randomProducts.Contains(product))
                {
                    randomProducts.Add(product);
                    count++;
                }
            }
        }
        products = randomProducts;


        if (products != null && products.Count > 0)
        {
            CaptionLabel.Text = this.Caption;
            ProductList.DataSource = products;
            ProductList.DataBind();
        }
        else
        {
            this.Visible = false;
        }
    }

    protected string GetThumbnailUrl(object thumbnailUrl)
    {
        if (!string.IsNullOrEmpty((string)thumbnailUrl)) return (string)thumbnailUrl;
        return "~/images/thumbs/ProductThumbnail.gif";
    }
}
and the Gold file

Code: Select all

namespace AbleCommerce.ConLib
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Web.UI.WebControls.WebParts;
    using CommerceBuilder.Products;
    using CommerceBuilder.UI;

    [Description("Display top seller products.")]    
    public partial class PopularProductsDialog : System.Web.UI.UserControl, ISidebarControl
    {
        private string _Caption = "Top Sellers";
        private int _MaxItems = 3;
        private int _Columns = -1;

        [Personalizable(), WebBrowsable()]
        [Browsable(true), DefaultValue(1)]
        [Description("The number of columns to display.")]
        public int Columns
        {
            get
            {
                if (_Columns < 0) return ProductList.RepeatColumns;
                return _Columns;
            }
            set
            {
                _Columns = value;
                ProductList.RepeatColumns = Columns;
            }
        }

        [Personalizable(), WebBrowsable()]
        [Browsable(true), DefaultValue("Top Sellers")]
        [Description("Caption / Title of the control")]
        public string Caption
        {
            get { return _Caption; }
            set { _Caption = value; }
        }

        [Personalizable(), WebBrowsable()]
        [Browsable(true), DefaultValue(3)]
        [Description("The maximum number of products that can be shown.")]
        public int MaxItems
        {
            get { return _MaxItems; }
            set { _MaxItems = value; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            int prefferedCategoryId = AbleCommerce.Code.PageHelper.GetCategoryId();
            IList<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
            if (products != null && products.Count > 0)
            {

                ProductList.RepeatColumns = Columns;
                ProductList.DataSource = products;
                ProductList.DataBind();
            }
            else
            {
                this.Visible = false;
            }
        }
    }
}

Re: Controlling Popular Products

Posted: Wed Sep 18, 2013 8:16 am
by jguengerich
I don't see any obvious problems in the code. If the customized code is copied from AC7's Page_Load method to Gold's Page_Load method, the file for Gold would look like this:

Code: Select all

    namespace AbleCommerce.ConLib
    {
        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Web.UI.WebControls.WebParts;
        using CommerceBuilder.Products;
        using CommerceBuilder.UI;

        [Description("Display top seller products.")]   
        public partial class PopularProductsDialog : System.Web.UI.UserControl, ISidebarControl
        {
            private string _Caption = "Top Sellers";
            private int _MaxItems = 3;
            private int _Columns = -1;

            [Personalizable(), WebBrowsable()]
            [Browsable(true), DefaultValue(1)]
            [Description("The number of columns to display.")]
            public int Columns
            {
                get
                {
                    if (_Columns < 0) return ProductList.RepeatColumns;
                    return _Columns;
                }
                set
                {
                    _Columns = value;
                    ProductList.RepeatColumns = Columns;
                }
            }

            [Personalizable(), WebBrowsable()]
            [Browsable(true), DefaultValue("Top Sellers")]
            [Description("Caption / Title of the control")]
            public string Caption
            {
                get { return _Caption; }
                set { _Caption = value; }
            }

            [Personalizable(), WebBrowsable()]
            [Browsable(true), DefaultValue(3)]
            [Description("The maximum number of products that can be shown.")]
            public int MaxItems
            {
                get { return _MaxItems; }
                set { _MaxItems = value; }
            }

            protected void Page_Load(object sender, EventArgs e)
            {
                int prefferedCategoryId = AbleCommerce.Code.PageHelper.GetCategoryId();
                //List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
                List<Product> products = ProductDataSource.GetPopularProducts(20, 7);
                List<Product> randomProducts = new List<Product>();
                Random random = new Random();
                int count = 0;
                if (products.Count > 0)
                {
                    if (MaxItems > products.Count)
                        MaxItems = products.Count;
                    while (count < MaxItems)
                    {
                        int index = random.Next(0, products.Count);
                        Product product = products[index];
                        if (!randomProducts.Contains(product))
                        {
                            randomProducts.Add(product);
                            count++;
                        }
                    }
                }
                products = randomProducts;


                if (products != null && products.Count > 0)
                {

                    ProductList.RepeatColumns = Columns;
                    ProductList.DataSource = products;
                    ProductList.DataBind();
                }
                else
                {
                    this.Visible = false;
                }
            }
        }
    }
If you get an error using that code, post the error message here and maybe we can figure it out.

Re: Controlling Popular Products

Posted: Wed Sep 18, 2013 3:48 pm
by Brewhaus
Well, it is a step in the right direction. The page loads, but there is an error where the products are supposed to be displayed:

[[ConLib:Custom/PopularProductsDialog]] e:\Websites\ACGold Site\Hot Sauce Depot\ConLib\Custom\PopularProductsDialog.ascx.cs(57): error CS0266: Cannot implicitly convert type 'System.Collections.Generic.IList' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)

Re: Controlling Popular Products

Posted: Mon Sep 23, 2013 2:28 pm
by jguengerich
Sorry for the delayed response, I had to tweak a few iPad apps for iOS 7.

The line:

Code: Select all

List<Product> products = ProductDataSource.GetPopularProducts(20, 7);
should be

Code: Select all

IList<Product> products = ProductDataSource.GetPopularProducts(20, 7);
I didn't catch it because the original AbleCommerce line that you commented out:

Code: Select all

//List<Product> products = ProductDataSource.GetPopularProducts(this.MaxItems, prefferedCategoryId);
Should also start with "IList" instead of "List", but the "I" is missing in the first two messages you posted that have code in them.
You might want to put the "I" back in the commented line in case you ever want to switch back to original code.

Re: Controlling Popular Products

Posted: Mon Sep 23, 2013 2:59 pm
by Brewhaus
Thank you, Jay. That got it working. :-)