Add a Grid View, Object DataSource and a dropdown to a web form. Also you will need a class which has two methods with different names and can be marked as SelectMethod (return a List Here is my sample web form: |
<asp:DropDownList ID="ddProductCategory" runat="server"
onselectedindexchanged="ddProductCategory_SelectedIndexChanged"
AutoPostBack="true">
<asp:ListItem Value="0">All Categories</asp:ListItem>
<asp:ListItem Value="1">Electronics</asp:ListItem>
</asp:DropDownList>
asp:Panel>
<asp:Panel ID="pnlProducts" runat="server" GroupingText="Products:">
<asp:GridView ID="grdProducts"
runat="server"
DataSourceID="odsProducts"
AutoGenerateColumns="true"
AllowPaging="true"
PageSize="2">
asp:GridView>
<asp:ObjectDataSource ID="odsProducts" runat="server"
DataObjectTypeName="string"
TypeName="WebApplication2.ProductsCollection"
SelectMethod="SelectAll">
asp:ObjectDataSource>
asp:Panel>
Here is the code in the code behind:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ddProductCategory_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.ddProductCategory.SelectedValue == "0")
{
// Select all products from all categories
// SelectAll() doesn't take any parameters.
this.odsProducts.SelectMethod = "SelectAll";
this.odsProducts.SelectParameters.Clear();
}
else
{
this.odsProducts.SelectMethod = "GetByCategoryID";
this.odsProducts.SelectParameters.Clear();
// Pass category id:
this.odsProducts.SelectParameters.Add("categoryID", TypeCode.Int32, "1");
}
}
And finally the sample class:
public class ProductsCollection
{
public ProductsCollection() { }
public List<string> SelectAll()
{
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
retList.Add("Tomatoes");
return retList;
}
public List<string> GetByCategoryID(int categoryID)
{
// We will imagine that here we have some processing based on
// categoryid.
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
return retList;
}
}
What we want to achieve here?
Well, we simply want to display all products from all categories when the user loads the page for the first time. Then we want to give him / her a way to narrow down the results, by selecting a concrete category of products (in our case there is only one category named “Electronics”
The most logical is to change the SelectMethod of the ObjectDataSource from SelectAll() to GetByCategoryID and vise versa.
And, yes, at first sight it seems to work like a charm. But try to navigate to the second page of the GridView (I made the PageSize to be 2 items so the paging control can appear).
You will receive exception in some cases. To see do the following.
1. Refresh the page so you can start from the beginning.
2. Select “Electronics” from the Categories Dropdown.
3. Click on page 2 in the GridView.
Where is the problem here?
As you may already noticed the ObjectDataSource is trying to invoke the Products using the SelectAll() method, passing it parameters for GetByCategoryID.
The reason is that the ObjectDataSource seems to maintain only the SelectParameters and get the SelectMethod from the markup. But for some reason this only happens when the GridView asks for rebind (PageIndex changed and Sorted events).
When you change in the dropdown selected index changed it works.
I have kind of workaround which I will post a bit later and it is not proven to work in all cases but did the trick for me.
4 comments:
Hi, Pavel !:)
I like this topic ! I will be glad to see your solution/workaround :-) GridViews are my favourite :)
-- Yosif
P.S. Just a suggestion - probably the changing of the SelectionMethod should be done on the Init/PreInit event, and then the GridView should be rebinded, because the DropDown SelectedIndexChanged is fired after the controls are bound to the page and no changes can be made ? What do you think ?
Hi, Yosif!
Glad you like it. First of all - if you have to change the Select method of a ObjectDataSource, this may indicate poor design so the first thing is to avoid this at all. If after all you need to do this, you are permitted to do it anywhere in the code (not quite sure, but I think the ObjectDataSource invokes its select after all page events are handled - Page_Load, SelectedIndexChanged of a control and so on, so you can change things meanwhile). I'll play a bit with the Init and PreInit events to see if there is a better solution than mine.
BTW - where does this love to GridViews come from ;-) ?
Hi, Paf:) Why don't you change directly GridView's DataSource, like this:
protected void BindData()
{
ProductsCollection products = new ProductsCollection();
if (this.ddProductCategory.SelectedValue == "0")
{
grdProducts.DataSource = products.SelectAll();
}
else
{
grdProducts.DataSource = products.GetByCategoryID(ddProductCategory.SelectedIndex);
}
grdProducts.DataBind();
}
The method should be invoked on GridView_PageIndexChanging and on DropDown_SelectedIndexChanged events. Also this way you get rid of ObjectDataSource. For initial DataBinding OnInit method should contain this:
protected override void OnInit(EventArgs e)
{
....
ProductsCollection products = new ProductsCollection();
grdProducts.DataSource = products.SelectAll();
grdProducts.DataBind();
}
Greets, lizzarde
Just put your code also in ObjectDataSource Selecting event and be careful that for the first dropdownlist item (like Select) value must be 0......and it will works in all situations
Post a Comment