The problem is not in the category tree. The tree itself works well. (Actually there are only few products on the site yet, because they are being entered)
The problem is in adding or editing Products itself.
When we try to save a product the admin interface almost stalls. This only occurs when a high number of categories has been created.
At first I assumed the problem to be the nested loop while loading the product categories. However this assumption appeared to be wrong. I have finally isolated the problem to be caused by the categorymapping datagrid bind method. Because it loads to many categories the loading gets unacceptably slow.
Implementing paging in this gridView seems to solve the issue.
I have modified the gridView declaration in productCategories.ascx as followed:
/// <summary> /// Remembers the values that have been checked in the gridview during paging /// The checked values will be temporarily stored in the users session /// </summary> private void RememberOldValues() { ArrayList categoryIDList = new ArrayList(); foreach (GridViewRow row in gvCategoryMappings.Rows) { CheckBox cbCategoryInfo = row.FindControl("cbCategoryInfo") as CheckBox; HiddenField hfCategoryID = row.FindControl("hfCategoryID") as HiddenField; int categoryID = int.Parse(hfCategoryID.Value); bool result = cbCategoryInfo.Checked;
// Check in the Session if (Session["CHECKED_ITEMS"] != null) { categoryIDList = (ArrayList)Session["CHECKED_ITEMS"]; }
if (result == true) { if (!categoryIDList.Contains(categoryID)) { categoryIDList.Add(categoryID); } } else { categoryIDList.Remove(categoryID); } } if (categoryIDList != null && categoryIDList.Count > 0) { Session["CHECKED_ITEMS"] = categoryIDList; } }
/// <summary> /// Restores the checked values in the gridview that have been previously selected on the current page /// (But have not been saved yet) /// </summary> private void RePopulateValues() { ArrayList categoryIDList = (ArrayList)Session["CHECKED_ITEMS"]; if (categoryIDList != null && categoryIDList.Count > 0) { foreach (GridViewRow row in gvCategoryMappings.Rows) { HiddenField hfCategoryID = row.FindControl("hfCategoryID") as HiddenField; int categoryID = int.Parse(hfCategoryID.Value);
if (categoryIDList.Contains(categoryID)) { CheckBox cbCategoryInfo = row.FindControl("cbCategoryInfo") as CheckBox; cbCategoryInfo.Checked = true; } } } }
The RememberOldValues and RepopulateValues are required to retain the checked entries during paging. However when clicking the save button, at this moment the checked values on pages, other then the currently selected page, get lost. I am trying to solve this issue. (Probably this requires loading the checked entries from the session in the save method)
I will update you when the issue has been resolved. It is likely that the same code will have to be implemented in the product variants and related products pages as this will give the same issue when a high number of items exist.
I have been able to fix the problem by implementing paging in the category mapping gridview.
I had to modify several methods in the productcategory.ascx codebehind file for this to be working. Is there any way I can submit this code so that you guys can review it and, if necessary, include it in the next release?
I have the same problem - slow work of product details page in admin area. I have about 80 manufactures, 100 categories, 1 image (~60kb) and my overall page size is about 3Mb! The page itself - 1.9Mb. I think this problem is not only about categories...
I appreciate what you have created. It inspired me to implement it. I was accomplishing the same thing with javascript but I had to turn off page validation to accomplish it. I store values in a Dictionary list with key values and text values of the checkbox and when I save the collection I can loop through the new Dictionary. The project I am working on is a Content Management System for a college and I was stumped on how to handle GridViews with paging. Here is the code that I developed for a grid view for Departments that accomplishes everything you did:
public Dictionary<int, string> Departments { get { if (ViewState["departments"] != null) return (Dictionary<int, string>)ViewState["departments"]; else return new Dictionary<int, string>(); } set { ViewState["departments"] = value; } }