I am using a UserControl as a WebPart and the UserControl contains a ListView a DataPager, and an ObjectDataSource. In the markup the DataPager comes first followed by the ListView like so:
This works without issue for WebParts that I declaratively add to the page at design time. If I try to add a new part to the page via the Catalog I get the error:
IPageableItemContainer 'ListView1' not found.
If I switch the physical order of the markup on the page like so:
The error goes away and everything runs smoothly when adding a WebPart from the Catalog.
I would like to have the option of using the DataPager above, below, or both in relation to the ListView. Why does the physical order of he tags in the markup only affect the adding of a control from the Catalog? How can I prevent a DataPager physically
placed before the ListView to delay its FindPageableItemContainer method until all of the controls are loaded?
By debugging the OnInit event of the DataPager I can see that when this UserControl is used as a normal user control the ListView is in the Controls collection when the DataPager fires its OnInit event. When added via to a page via the Catalog the ListView
is NOT in the controls collection when the OnInit event fires. In fact, none of the other controls phsyically located below the DataPager are in the controls collection when the OnInit event fires.
Does anyone know if this is "normal" behavior for UserControls used as a WebPart, I've never had this problem before when using the other databound controls in the same manner.
This doesn't seem to be a very popular post, but just in case someone ever runs across the same issue, here is what I found:
The method that causes the problem is the FindPageableItemContainer method, which for some reason throws an exception when it can't find the control identifed by PagedSourceID
The OnInit method of the DataPager calls FindPageableItemContainer, as I stated in my previous post this works when the control identified by the PagedSourceID is already present on the page but would crash when it wasn't available.
The OnLoad method of the DataPager ALSO calls FindPageableItemContainer if it hasn't already been found.
My Solution: Since FindPageableItemContainer is called from several places within the DataPager, the code
calling this method should be responsible for handling the situation where the control is not found. To resolve my situation I created my own CustomDataPager that inherited from DataPager. In my custom version I overrode FindPageableItemContainer
and simply copied the orignal code and then commented out the lines that throw the exceptions which allows processing to continue when the PagedSourceID is not initially found. The FindPageableItemContainer method does eventually find the PagedSourceID control
when it is called by the default OnLoad method of the DataPager and everything works perfectly as far as I can tell.
Here is my code for the CustomDataPager, hope it helps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;
namespace CMSSite.CustomControls
{
/// <summary>
/// A CustomDataPager that will navigate the control tree to find the required control to page.
/// </summary>
public class CustomDataPager : DataPager
{
//this code is the same as the default method, only the exceptions
//have been commented out to prevent it from throwing an exception
//when it doesn't find the associated control
protected override IPageableItemContainer FindPageableItemContainer()
{
if (!string.IsNullOrEmpty(this.PagedControlID))
{
Control control = FindControlHelper(this, this.PagedControlID);
if (control == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_PageableItemContainerNotFound, new object[] { this.PagedControlID }));
}
IPageableItemContainer container = control as IPageableItemContainer;
if (container == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_ControlIsntPageable, new object[] { this.PagedControlID }));
}
return container;
}
Control namingContainer = this.NamingContainer;
IPageableItemContainer container2 = null;
while ((container2 == null) && (namingContainer != this.Page))
{
if (namingContainer == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_NoNamingContainer, new object[] { this.ID }));
}
container2 = namingContainer as IPageableItemContainer;
namingContainer = namingContainer.NamingContainer;
}
return container2;
}
//this code was taken from the DataBoundControlHelper.FindControl method
protected Control FindControlHelper(Control control, string controlID)
{
Control namingContainer = control;
Control control3 = null;
if (control != control.Page)
{
while ((control3 == null) && (namingContainer != control.Page))
{
namingContainer = namingContainer.NamingContainer;
if (namingContainer == null)
{
throw new HttpException("Error finding control");
}
control3 = namingContainer.FindControl(controlID);
}
return control3;
}
return control.FindControl(controlID);
}
}
}
/// <summary>
/// A CustomDataPager that will navigate the control tree to find the required control to page.
/// </summary>
public class CustomDataPager : DataPager
{
//this code is the same as the default method, only the exceptions
//have been commented out to prevent it from throwing an exception
//when it doesn't find the associated control
protected override IPageableItemContainer FindPageableItemContainer()
{
if (!string.IsNullOrEmpty(this.PagedControlID))
{
Control control = FindControlHelper(this, this.PagedControlID);
if (control == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_PageableItemContainerNotFound, new object[] { this.PagedControlID }));
}
IPageableItemContainer container = control as IPageableItemContainer;
if (container == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_ControlIsntPageable, new object[] { this.PagedControlID }));
}
return container;
}
Control namingContainer = this.NamingContainer;
IPageableItemContainer container2 = null;
while ((container2 == null) && (namingContainer != this.Page))
{
if (namingContainer == null)
{
//throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_NoNamingContainer, new object[] { this.ID }));
}
container2 = namingContainer as IPageableItemContainer;
namingContainer = namingContainer.NamingContainer;
}
return container2;
}
//this code was taken from the DataBoundControlHelper.FindControl method
protected Control FindControlHelper(Control control, string controlID)
{
Control namingContainer = control;
Control control3 = null;
if (control != control.Page)
{
while ((control3 == null) && (namingContainer != control.Page))
{
namingContainer = namingContainer.NamingContainer;
if (namingContainer == null)
{
throw new HttpException("Error finding control");
}
// here we go - alvipeo
if (namingContainer is MasterPage)
{
MasterPage master = namingContainer as MasterPage;
IEnumerable<Control> allcontrols = master.Controls.All();
var placeHolders = from ph in allcontrols where ph is ContentPlaceHolder select ph;
foreach (ContentPlaceHolder cp in placeHolders)
{
control3 = cp.FindControl(controlID);
if (control3 != null)
return control3;
}
}
control3 = namingContainer.FindControl(controlID);
}
return control3;
}
return control.FindControl(controlID);
}
}
bdway01
Member
1 Points
19 Posts
DataPager outside ListView in WebPart - IPageableItemContainer not found.
Aug 12, 2009 08:57 PM|LINK
I am using a UserControl as a WebPart and the UserControl contains a ListView a DataPager, and an ObjectDataSource. In the markup the DataPager comes first followed by the ListView like so:
<DataPager PagedSourceID="ListView1"></DataPager>
<ListView ID="ListView1"></ListView>
This works without issue for WebParts that I declaratively add to the page at design time. If I try to add a new part to the page via the Catalog I get the error: IPageableItemContainer 'ListView1' not found.
If I switch the physical order of the markup on the page like so:
<ListView ID="ListView1"></ListView>
<DataPager PagedSourceID="ListView1"></DataPager>
The error goes away and everything runs smoothly when adding a WebPart from the Catalog.
I would like to have the option of using the DataPager above, below, or both in relation to the ListView. Why does the physical order of he tags in the markup only affect the adding of a control from the Catalog? How can I prevent a DataPager physically placed before the ListView to delay its FindPageableItemContainer method until all of the controls are loaded?
DataPager ListView WebPart
bdway01
Member
1 Points
19 Posts
Re: DataPager outside ListView in WebPart - IPageableItemContainer not found.
Aug 13, 2009 07:05 PM|LINK
By debugging the OnInit event of the DataPager I can see that when this UserControl is used as a normal user control the ListView is in the Controls collection when the DataPager fires its OnInit event. When added via to a page via the Catalog the ListView is NOT in the controls collection when the OnInit event fires. In fact, none of the other controls phsyically located below the DataPager are in the controls collection when the OnInit event fires.
Does anyone know if this is "normal" behavior for UserControls used as a WebPart, I've never had this problem before when using the other databound controls in the same manner.
bdway01
Member
1 Points
19 Posts
Re: DataPager outside ListView in WebPart - IPageableItemContainer not found.
Aug 14, 2009 05:15 PM|LINK
This doesn't seem to be a very popular post, but just in case someone ever runs across the same issue, here is what I found:
The method that causes the problem is the FindPageableItemContainer method, which for some reason throws an exception when it can't find the control identifed by PagedSourceID
The OnInit method of the DataPager calls FindPageableItemContainer, as I stated in my previous post this works when the control identified by the PagedSourceID is already present on the page but would crash when it wasn't available.
The OnLoad method of the DataPager ALSO calls FindPageableItemContainer if it hasn't already been found.
My Solution: Since FindPageableItemContainer is called from several places within the DataPager, the code calling this method should be responsible for handling the situation where the control is not found. To resolve my situation I created my own CustomDataPager that inherited from DataPager. In my custom version I overrode FindPageableItemContainer and simply copied the orignal code and then commented out the lines that throw the exceptions which allows processing to continue when the PagedSourceID is not initially found. The FindPageableItemContainer method does eventually find the PagedSourceID control when it is called by the default OnLoad method of the DataPager and everything works perfectly as far as I can tell.
anooptatti
Member
2 Points
1 Post
Re: DataPager outside ListView in WebPart - IPageableItemContainer not found.
Jan 13, 2010 04:58 AM|LINK
Hi,
Even I have the same problem. Can you please share the code of your customDataPager?
bdway01
Member
1 Points
19 Posts
Re: DataPager outside ListView in WebPart - IPageableItemContainer not found.
Jan 13, 2010 12:52 PM|LINK
Here is my code for the CustomDataPager, hope it helps.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Globalization; namespace CMSSite.CustomControls { /// <summary> /// A CustomDataPager that will navigate the control tree to find the required control to page. /// </summary> public class CustomDataPager : DataPager { //this code is the same as the default method, only the exceptions //have been commented out to prevent it from throwing an exception //when it doesn't find the associated control protected override IPageableItemContainer FindPageableItemContainer() { if (!string.IsNullOrEmpty(this.PagedControlID)) { Control control = FindControlHelper(this, this.PagedControlID); if (control == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_PageableItemContainerNotFound, new object[] { this.PagedControlID })); } IPageableItemContainer container = control as IPageableItemContainer; if (container == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_ControlIsntPageable, new object[] { this.PagedControlID })); } return container; } Control namingContainer = this.NamingContainer; IPageableItemContainer container2 = null; while ((container2 == null) && (namingContainer != this.Page)) { if (namingContainer == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_NoNamingContainer, new object[] { this.ID })); } container2 = namingContainer as IPageableItemContainer; namingContainer = namingContainer.NamingContainer; } return container2; } //this code was taken from the DataBoundControlHelper.FindControl method protected Control FindControlHelper(Control control, string controlID) { Control namingContainer = control; Control control3 = null; if (control != control.Page) { while ((control3 == null) && (namingContainer != control.Page)) { namingContainer = namingContainer.NamingContainer; if (namingContainer == null) { throw new HttpException("Error finding control"); } control3 = namingContainer.FindControl(controlID); } return control3; } return control.FindControl(controlID); } } }alvipeo
Member
12 Points
22 Posts
Re: DataPager outside ListView in WebPart - IPageableItemContainer not found.
Feb 06, 2011 05:58 PM|LINK
Changed your code to work in Master pages:
/// <summary> /// A CustomDataPager that will navigate the control tree to find the required control to page. /// </summary> public class CustomDataPager : DataPager { //this code is the same as the default method, only the exceptions //have been commented out to prevent it from throwing an exception //when it doesn't find the associated control protected override IPageableItemContainer FindPageableItemContainer() { if (!string.IsNullOrEmpty(this.PagedControlID)) { Control control = FindControlHelper(this, this.PagedControlID); if (control == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_PageableItemContainerNotFound, new object[] { this.PagedControlID })); } IPageableItemContainer container = control as IPageableItemContainer; if (container == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_ControlIsntPageable, new object[] { this.PagedControlID })); } return container; } Control namingContainer = this.NamingContainer; IPageableItemContainer container2 = null; while ((container2 == null) && (namingContainer != this.Page)) { if (namingContainer == null) { //throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.DataPager_NoNamingContainer, new object[] { this.ID })); } container2 = namingContainer as IPageableItemContainer; namingContainer = namingContainer.NamingContainer; } return container2; } //this code was taken from the DataBoundControlHelper.FindControl method protected Control FindControlHelper(Control control, string controlID) { Control namingContainer = control; Control control3 = null; if (control != control.Page) { while ((control3 == null) && (namingContainer != control.Page)) { namingContainer = namingContainer.NamingContainer; if (namingContainer == null) { throw new HttpException("Error finding control"); } // here we go - alvipeo if (namingContainer is MasterPage) { MasterPage master = namingContainer as MasterPage; IEnumerable<Control> allcontrols = master.Controls.All(); var placeHolders = from ph in allcontrols where ph is ContentPlaceHolder select ph; foreach (ContentPlaceHolder cp in placeHolders) { control3 = cp.FindControl(controlID); if (control3 != null) return control3; } } control3 = namingContainer.FindControl(controlID); } return control3; } return control.FindControl(controlID); } }