DataSource Problem for Nested DataList

  • Thread starter Thread starter scottls
  • Start date Start date
S

scottls

Hi All,

Thanks for reading my post. I have been working on getting nested
datalists working properly wihtin my framework for many days and I
think I'm almost there. See if you could help me get over the hump
here.

Some of our products come in different sizes - i.e. what I call
"units". Some products don't. I successfully created the first
datalist (called productList) to show our products with their general
description, but now I want to show the available units for the
products (called productUnits). So what I'm doing is nesting two
datalists, using the ItemDataBound event on the outer datalist.

I've walked through in debug mode and I am successfully retreiving the
units, but I get an error when I declare the datasource for the
datalist "productUnits". I am getting the following error:
"An invalid data source is being used for productUnits. A valid data
source must implement either IListSource or IEnumerable."

Here is the code. Can you help? Thanks is advance!!

Scott L. Smeester
TIDF

===========================
ProductList.aspx
===========================

<asp:DataList ID="productList" runat="server" RepeatColumns="1"
RepeatDirection="Horizontal" OnItemDataBound="list_ItemDataBound"
DataKeyField="ProductID">
<ItemTemplate>
<a href='<%# "~/Products/ProductPage.aspx?ProductID=" +
Eval("ProductID") %>' runat="server" >
<%# Eval("ProductName") %>
</a>
<br />
<%# Eval("BriefDesc") %>
<br />
<asp:DataList ID="productUnits" runat="server" Visible="false">
<ItemTemplate>
<asp:Label ID="lblUnitName" runat="server"><%#
Eval("UnitName") %></asp:Label>
</ItemTemplate>
</asp:DataList>
</ItemTemplate>
</asp:DataList>

===========================
ProductList.aspx.cs
===========================

protected void list_ItemDataBound(object sender, DataListItemEventArgs
e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
// if this product has units, show the different sizes
bool unitsYN =
Convert.ToBoolean(((DataRowView)e.Item.DataItem).Row.ItemArray[3].ToString());

if (unitsYN == true)
{
// get the current productID
string productID =
Convert.ToString(((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString());

// find the datalist
DataList productUnits =
(DataList)e.Item.FindControl("productUnits");

// retrieve the data
productUnits.DataSource =
CatalogAccess.GetProductUnits(productID);
productUnits.DataBind();

}
}
}

===========================
CatalogAccess.cs
===========================

public struct ProductUnits
{
public string UnitName;
}

public class CatalogAccess
{
// get product details
public static ProductUnits GetProductUnits(string productID)
{
// get a configured DbCommand object
DbCommand comm = GenericDataAccess.CreateCommand();
// set the store procedure name
comm.CommandText = "GetProductUnits";
// create a new paramater
DbParameter param = comm.CreateParameter();
param.ParameterName = "@ProductID";
param.Value = productID;
param.DbType = DbType.Int32;
comm.Parameters.Add(param);
// execute the store procedure
DataTable table = GenericDataAccess.ExecuteSelectCommand(comm);
// wrap retrieved data into a CategoryDetails object
ProductUnits prodUnitDetails = new ProductUnits();
if (table.Rows.Count > 0)
{
// get the first table row
DataRow dr = table.Rows[0];
// get product details
prodUnitDetails.UnitName = dr["UnitName"].ToString();
}
// return department details
return prodUnitDetails;
}
}

===========================
GenericDataAccess.cs
===========================

public class GenericDataAccess
{
// executes a command and returns the results as a DataTable object
public static DataTable ExecuteSelectCommand(DbCommand command)
{
// The DataTable to be returned
DataTable table;

// Execute the command making sure the connection gets closed
in the end
try
{
// Open the data connection
command.Connection.Open();

// Execute the command and save the results in a DataTable
DbDataReader reader = command.ExecuteReader();
table = new DataTable();
table.Load(reader);

// Close the reader
reader.Close();
}
catch (Exception ex)
{
Utilities.LogError(ex);
throw ex;
}
finally
{
// Close the connection
command.Connection.Close();
}
return table;
}
}

===========================
GetProductUnits Stored Procedure
===========================

ALTER PROCEDURE GetProductUnits
(@ProductID INT)
AS
SELECT UnitName
FROM ProductUnits
WHERE ProductID = @ProductID AND LiveYN = 'True'
RETURN

===========================
END POSTING
===========================
 
Hello again,

Well, I've gotten a little further. I'll post what I've found out so
far but I have ran into another problem. When debugging, "pu.UnitName"
resolves to a value I am expecting, i.e. the unit name, however I think
it is throwing a null exception (ya think?). I'm getting this error
now:
"NullReferenceException was unhandled by user code
Object reference not set to an instance of an object."

Thanks for your help!

Scott

=========================================
New "list_ItemDataBound" event:
=========================================

protected void list_ItemDataBound(object sender, DataListItemEventArgs
e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
// if this product has units, show the different sizes
bool unitsYN =
Convert.ToBoolean(((DataRowView)e.Item.DataItem).Row.ItemArray[3].ToString(­));


if (unitsYN == true)
{
// get the current productID
string productID =
Convert.ToString(((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString()­);


// find the datalist
DataList productUnits =
(DataList)e.Item.FindControl("productUnits");

// make the datalist visible
productUnits.Visible = true;

// stores product details
ProductUnits pu;
pu = CatalogAccess.GetProductUnits(productID);

// find the label controls
Label lblUnitName =
(Label)e.Item.FindControl("lblUnitName");

// display product details
lblUnitName.Text = pu.UnitName;
}
}
}

=========================================
END POSTING
=========================================
 
I finally figured it out how to nest datalists (the way I wanted to do
it). And since I spent a lot of time researching the forums and trying
many different things, I want to make sure that the person who is
trying to do the same can see what I did. I owe this one!!

Note:
Disregard my follow up message with the "New list_ItemDataBound event"
because I could not figure out how to locate the "lblUnitName" label to
set the unit data to it and that is now I wanted to do it anyways. My
original problem was because I could not bind the data I had received
to the datalist, but that is because I was trying to use a "struct",
which doesn't work, because many of our products have more than one
unit.

Here is the complete functioning code:


===========================
ProductList.aspx
===========================

<asp:DataList ID="productList" runat="server" RepeatColumns="1"
RepeatDirection="Horizontal" OnItemDataBound="list_ItemDataBound"
DataKeyField="ProductID">
<ItemTemplate>
<a href='<%# "~/Products/ProductPage.aspx?ProductID=" +
Eval("ProductID") %>' runat="server" >
<%# Eval("ProductName") %>
</a>
<br />
<%# Eval("BriefDesc") %>
<br />
<asp:DataList ID="productUnits" runat="server" Visible="false">
<ItemTemplate>
<asp:Label ID="lblUnitName" runat="server"><%#
Eval("UnitName") %></asp:Label>
</ItemTemplate>
</asp:DataList>
</ItemTemplate>
</asp:DataList>

===========================
ProductList.aspx.cs
===========================

protected void list_ItemDataBound(object sender, DataListItemEventArgs
e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
// if this product has units, show the different sizes
bool unitsYN =
Convert.ToBoolean(((DataRowView)e.Item.DataItem).Row.ItemArray[3].ToString());

if (unitsYN == true)
{
// get the current productID
string productID =
Convert.ToString(((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString());

// find the datalist
DataList productUnits =
(DataList)e.Item.FindControl("productUnits");

// make the datalist visible
productUnits.Visible = true;

// locate and bind data
productUnits.DataSource =
CatalogAccess.GetProductUnits(productID);
productUnits.DataBind();

}
}
}

===========================
*REVISED* CatalogAccess.cs
===========================

public class CatalogAccess
{
// get product details
public static DataTable GetProductUnits(string productID)
{
// get a configured DbCommand object
DbCommand comm = GenericDataAccess.CreateCommand();
// set the store procedure name
comm.CommandText = "GetProductUnits";
// create a new paramater
DbParameter param = comm.CreateParameter();
param.ParameterName = "@ProductID";
param.Value = productID;
param.DbType = DbType.Int32;
comm.Parameters.Add(param);
// execute the store procedure
return GenericDataAccess.ExecuteSelectCommand(comm);
}
}

===========================
GenericDataAccess.cs
===========================

public class GenericDataAccess
{
// executes a command and returns the results as a DataTable object
public static DataTable ExecuteSelectCommand(DbCommand command)
{
// The DataTable to be returned
DataTable table;

// Execute the command making sure the connection gets closed
in the end
try
{
// Open the data connection
command.Connection.Open();

// Execute the command and save the results in a DataTable
DbDataReader reader = command.ExecuteReader();
table = new DataTable();
table.Load(reader);

// Close the reader
reader.Close();
}
catch (Exception ex)
{
Utilities.LogError(ex);
throw ex;
}
finally
{
// Close the connection
command.Connection.Close();
}
return table;
}
}

===========================
GetProductUnits Stored Procedure
===========================

ALTER PROCEDURE GetProductUnits
(@ProductID INT)
AS
SELECT UnitName
FROM ProductUnits
WHERE ProductID = @ProductID AND LiveYN = 'True'
RETURN

===========================
END POSTING
===========================
 
Back
Top