Wednesday, March 21, 2012

CascadingDropDown questions

I have 2 DropDownLists. One for categories and the other one for subcategories. When I change a category I want the subcategories to change. I thought this could be accomplished using the CascadingDropDown extender but I'm facing some problems.

I have populated (in the Page_Load method) both dropdownlists but the web service gets called to populate the dropdownlists. Is there any way to make the extender only call the webservice when the selection changes if it's populated with data?

Another question is why the webservice is called 3 times at start up, one for the categories (knownCategoryValues = "", category = "categories"), and two for the subcategories (knownCategoryValues = "categories:", category = "subcategories" and knownCategoryValues = "categories:1", category = "subcategories").

I thought it would be called twice not three times.

BTW, there is a helper method to return values using an xml document:

AtlasControlToolkit.CascadingDropDown.QuerySimpleCascadingDropDownDocument

please add something similar to extract values from a DataTable.

Thanks.

The short answer is that we need to do some optimization around how many times the webservice is called. It's currently called three times because:

1) Once to populate the first list

2) Once to populate the second list

3) Once when the second list detects the value of the first list has changed

So there's some work do be done, and what you're seeing is an early version. In any case, you should apply some caching to your web service to improve performance (seehttp://support.microsoft.com/?scid=kb;en-us;318299).


Thanks for the reply Shawn but my main problem was this:

I have populated (in the Page_Load method) both dropdownlists but the web service gets called after to populate again the dropdownlists.

Is there any way to make the extenderonlycall the webservice when the selection changes if the dropdownlist is already populated with data?

And now that you have mentioned caching the web service. I was already caching my web service but I was wondering if Atlas does some kind of client caching when calling a web service if the web service is cached?

Thanks,
Manu


Yeah - the fix in the toolkit is pretty easy. Open CascadingDropDownBehavior.js, and find the "_onParentChange" method. Replace it with this:

var _lastParentValues;this._onParentChange = function() { var e =this.control.element;// Create the known category/value pairs string for sending to the helper web service // Follow parent pointers so that the complete state can be sent // Format: 'name1:value1;name2:value2;...' var knownCategoryValues =''; var parentControlID = _parentControlID;while (parentControlID) { var parentElement = document.getElementById(parentControlID);if (parentElement && (-1 != _parentElement.selectedIndex)) { knownCategoryValues = parentElement.CascadingDropDownCategory +':' + parentElement.options[parentElement.selectedIndex].value +';' + knownCategoryValues; parentControlID = parentElement.CascadingDropDownParentControlID; }else { parentControlID =null; } }if (knownCategoryValues !='' && _lastParentValues == knownCategoryValues) {return; } _lastParentValues = knownCategoryValues;// Call the helper web service Sys.Net.ServiceMethod.invoke( _servicePath, _serviceMethod,null, {'knownCategoryValues' : knownCategoryValues,'category' : _category }, Function.createDelegate(this, _onMethodComplete), Function.createDelegate(this, _onMethodTimeout), Function.createDelegate(this, _onMethodError), Function.createDelegate(this, _onMethodAborted),this ); }

It is not working Shawn.

I have made a simple example so you can test it yourself quickly:

---- BEGIN Example.aspx ---

<%@.PageLanguage="C#"AutoEventWireup="true"CodeFile="Example.aspx.cs"Inherits="Example"%>

<%@.RegisterAssembly="AtlasControlToolkit"Namespace="AtlasControlToolkit"TagPrefix="cc1"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">

<headrunat="server">

<title>Untitled Page</title>

</head>

<body>

<formid="form1"runat="server">

<div>

<cc1:cascadingdropdownid="CascadingDropDown1"runat="server">

<cc1:CascadingDropDownPropertiesTargetControlID="ddlCategorias"Category="categorias"ServiceMethod="GetCategorias"ServicePath="Example.asmx"/>

<cc1:CascadingDropDownPropertiesTargetControlID="ddlSubcategorias"Category="subcategorias"ServiceMethod="GetSubcategorias"ServicePath="Example.asmx"ParentControlID="ddlCategorias"/>

</cc1:cascadingdropdown>

</div>

<atlas:ScriptManagerID="ScriptManager1"runat="server">

</atlas:ScriptManager>

<asp:DropDownListID="ddlCategorias"runat="server"DataTextField="Nombre"DataValueField="IdCat">

</asp:DropDownList>

<asp:DropDownListID="ddlSubcategorias"runat="server"DataTextField="Nombre"DataValueField="IdCat">

</asp:DropDownList>

</form>

</body>

</html>

---- END Example.aspx ---


---- BEGIN Example.aspx.cs ---

using System;

using System.Data;

using System.Configuration;

using System.Collections;

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;

publicpartialclassExample : System.Web.UI.Page

{

protectedvoid Page_Load(object sender,EventArgs e)

{

ddlCategorias.DataSource = GetCategoriasPrimerNivel();

ddlCategorias.DataBind();

ddlCategorias.SelectedValue ="1";

ddlSubcategorias.DataSource = GetSubcategorias(1);

ddlSubcategorias.DataBind();

ddlSubcategorias.SelectedValue ="10";

}

privateCategoria[] GetCategoriasPrimerNivel()

{

Categoria[] categorias =newCategoria[5];

for (int i = 0; i < categorias.Length; i++) {

categorias[i] =newCategoria(i,"CAT " + i);

}

return categorias;

}

privateCategoria[] GetSubcategorias(int p)

{

Categoria[] subcategorias =newCategoria[10];

for (int i = 0; i < subcategorias.Length; i++) {

subcategorias[i] =newCategoria(i + 5,"SUBCAT (" + p +", " + i +")");

}

return subcategorias;

}

}

---- END Example.aspx.cs ---

---- BEGIN Example.asmx ---

<%

@.WebServiceLanguage="C#"CodeBehind="~/App_Code/Example.cs"Class="Example" %>

---- END Example.asmx ---

---- BEGIN Example.cs ---

using System;

using System.Web;

using System.Collections;

using System.Collections.Specialized;

using System.Web.Services;

using System.Web.Services.Protocols;

///<summary>

/// Summary description for Example

///</summary>

[WebService(Namespace ="http://tempuri.org/")]

[WebServiceBinding(ConformsTo =WsiProfiles.BasicProfile1_1)]

publicclassExample : System.Web.Services.WebService {

public Example () {

//Uncomment the following line if using designed components

//InitializeComponent();

}

[WebMethod]

public AtlasControlToolkit.CascadingDropDownNameValue[] GetCategorias(string knownCategoryValues,string category)

{

// Get a dictionary of known category/value pairs

StringDictionary knownCategoryValuesDictionary = AtlasControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

Categoria[] categorias = GetCategoriasPrimerNivel();

AtlasControlToolkit.CascadingDropDownNameValue[] returnValue =new AtlasControlToolkit.CascadingDropDownNameValue[categorias.Length];

for (int i = 0; i < categorias.Length; i++) {

returnValue[i] =new AtlasControlToolkit.CascadingDropDownNameValue("WS_" + categorias[i].Nombre, categorias[i].IdCat.ToString());

}

return returnValue;

}

[WebMethod]

public AtlasControlToolkit.CascadingDropDownNameValue[] GetSubcategorias(string knownCategoryValues,string category)

{

// Get a dictionary of known category/value pairs

StringDictionary knownCategoryValuesDictionary = AtlasControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

string str = knownCategoryValuesDictionary["categorias"];

Categoria[] subcategorias = GetSubcategorias(Int32.Parse(str));

AtlasControlToolkit.CascadingDropDownNameValue[] returnValue =new AtlasControlToolkit.CascadingDropDownNameValue[subcategorias.Length];

for (int i = 0; i < subcategorias.Length; i++) {

returnValue[i] =new AtlasControlToolkit.CascadingDropDownNameValue("WS_" + subcategorias[i].Nombre, subcategorias[i].IdCat.ToString());

}

return returnValue;

}

privateCategoria[] GetCategoriasPrimerNivel()

{

Categoria[] categorias =newCategoria[5];

for (int i = 0; i < categorias.Length; i++) {

categorias[i] =newCategoria(i,"CAT " + i);

}

return categorias;

}

privateCategoria[] GetSubcategorias(int p)

{

Categoria[] subcategorias =newCategoria[10];

for (int i = 0; i < subcategorias.Length; i++) {

subcategorias[i] =newCategoria(i + 5,"SUBCAT (" + p +", " + i +")");

}

return subcategorias;

}

}

---- END Example.cs ---

Note that I have bound both dropdownlists at Page_Load with values CAT XXX and SUBCAT XXX.

However when you run the sample you get WS_CAT XXX and WS_SUBCAT XXX that are the values returned by the web service.


Hi Manuel,

I think we've fixed the issue you're having with the latest version of the toolkit. I'd recommend you get that installed and see if it makes it work.

Thanks,
Ted

No comments:

Post a Comment