Kentico CmsRepeater: When to call databind when DataBindByDefault="false" - asp.net

I want to set DataBindByDefault to false on my repeater because otherwise it makes a call to the db which returns all data from the child nodes of the page which comes to 12MB.
I've hacked it for now and set the Path value to "." (same page only) in the code in front but it's still an extra db call.
So my plan was to set DataBindByDefault to false, assign the data from my custom query to the repeater and then call databind() as follows:
<cms:CMSRepeater ID="repItems" runat="server" Path="."/>
private void InitRepeater()
{
var data = (DataSet)NewsProvider.GetNews(ClassNames, Path, MaxRelativeLevel, OrderBy, WhereStatement, SelectTopN, -1, -1);
if (!DataHelper.DataSourceIsEmpty(data))
{
repItems.DataSource = data;
repItems.ControlContext = ControlContext;
repItems.EnablePaging = true;
repItems.PageSize = PageSize;
repItems.PagerControl.CurrentPage = 1;
repItems.PagerControl.PageSize = PageSize;
repItems.PagerControl.Visible = false;
repItems.HideControlForZeroRows = true;
repItems.TransformationName = Transformation;
repItems.DataBind();
}
}
InitRepeater() is called from SetupControl() which called from OnContentLoaded() and ReloadData() but nothing gets rendered.
If I try calling InitRepeater() in PreRender it renders but it ignores the paging settings.
I'm using Kentico v12.0.65

You should be using the LoadPagesIndividually property of the repeater control. If true, each page is loaded individually in case of paging.

Related

Unable to display values in ListBox from static method

On Static WebMethod I'm unable to get ListBoxcontrol, so I have stored that control in session on Page_Load event as:
HttpContext.Current.Session["LB_AvailFields"] = lbavailablefields;
After calling WebMethod I'm getting values from Database and trying to fill ListBox but ListBox not showing any values.
Following is hardcoded testing code which works fine on Page_Load but not in WebMethod please suggest where I'm going wrong?
List<MyListItem> LB = new List<MyListItem>();
MyListItem lbitem;
for(int i= 0;i<5;i++)
{
lbitem = new MyListItem();
lbitem.PMKey = "Key" + i;
lbitem.PMSystemName = "SystemName: " + i;
LB.Add(lbitem);
}
ListBox lbox = (ListBox)HttpContext.Current.Session["LB_AvailFields"];
lbox.DataSource = LB;
lbox.DataTextField = "PMSystemName";
lbox.DataValueField = "PMKey";
lbox.DataBind();
The WebMethod concept is to give you a quick web service like experience. The web page doesn't exist on the server, as it does when Page_Load works. The intended use is to call web methods from client script, return data to client side and consume there (javascript)
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public MyReturnResultObject[] GetListBoxData()
{
List<MyReturnResultObject> result = new List<MyReturnResultObject>();
loop to fill your return result
{
var oneResult = new MyReturnResultObject();
...
result.Add(oneResult);
}
return result.toArray();
}
Then on the client side, where you use javascript to call that method, just use the returned json to populate your listbox (using javascript). There are many ways to do this in javascript, showing most rudimentary; if jQuery is available to you you could use it.
var myList = ...; // obtain a reference to your list box
var anOption;
loop through json
anOption = document.createElement("Option");
anOption.text = ...; //from json
anOption.value = ...; //from json
myList.add(anOption);

ASP.NET control lifecycle. Control property changes only available on next load

I have built a pager control with various properties, for example Start to indicate the first record which should be rendered. This is embedded in another control which actually renders the list of records. The properties' getters and setters use ViewState to persist and retrieve the values.
The links in the pager are dynamically created during the page_load. On each link, the anchor.ServerClick delegate is wired up to a lambda that sets the Start property on the pager control.
When I debug the page, I can see that the Start property is indeed updated, but that the changed value is only available the next time I load the page, presumably persisted via the ViewState mechanism.
What this means in practice is that the embedding control doesn't see the updated values of these properties in time to render the correct list. How can I have the visitor's click update the pager properties before they get used rather than afterwards?
EDIT: adding some code
Called from the Page_Load of the main control, I have a loop that references the properties of the pager. This loop determines the items which will be displayed, and if the control properties were updated by this point, it would display the correct records, but that's not the case.
for (int i = pager.Start - 1 ;
i < queryResults.Count() && i <= (pager.Start + pager.PageSize); i++) {
In the pager control, also called from the Page_Load, there's code like this, that adds child controls and wires up the delegate.
HtmlAnchor a = new HtmlAnchor();
a.HRef = "#";
a.InnerText = page.ToString();
newStartNumber = ((page - 1) * this.PageSize) + 1;
a.Attributes["data-start"] = newStartNumber.ToString();
a.ServerClick += (sender, e) =>
{ this.Start = int.Parse(((HtmlAnchor)sender).Attributes["data-start"]); };
li.Controls.Add(a);
ul.Controls.Add(li);
So when these anchors are clicked, the pager's Start property is updated, but it's too late.
As far as I know, these code parts seem ok, provided :
Your Page property looks like this :
public int Page
{
get { return ViewState["Page"] == null ? 0: (int)ViewState["Page"]; }
set { ViewState["Page"] = value; }
}
and this :
for (int i = pager.Start - 1 ;
i < queryResults.Count() && i <= (pager.Start + pager.PageSize); i++) {
is in the preRender of your parent control.
And this :
HtmlAnchor a = new HtmlAnchor();
a.HRef = "#";
a.InnerText = page.ToString();
newStartNumber = ((page - 1) * this.PageSize) + 1;
a.ServerClick += (sender, e) => { this.Start = newStartNumber; };
li.Controls.Add(a);
ul.Controls.Add(li);
is in the pageload (or init) of your pager control. (maybe you don't need the data-start attribute)
You should give Ids to your HtmlAnchors.

Object reference not set to an instance of an object error

I have Default.aspx and Upload.aspx.
I'm passing Id through query string to default.aspx(like:http://localhost:3081/default.aspx?Id=1752).In default page i have a link button to open the upload.aspx to upload file.When i use the Request.QueryString["Id"] in upload.aspx,it is showiing error as "Object reference not set to an instance of an object".I'm dealing with RadControls.
To open when i click a link(OnClientClick="return ShowAddFeedBackForm()") i have code like:
<script>
function ShowAddFeedBackForm() {
window.radopen("Upload.aspx", "UserListDialog");
return false;
}
</script>
I'm using detailsview in upload page with a textbox and a fileupload control.
code to bind when a file upload in upload.aspx
protected void DetailsView1_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
string qString = Request.QueryString["Id"].ToString();
if (DetailsView1.CurrentMode == DetailsViewMode.Insert)
{
//string qString = Request.QueryString["Id"].ToString();
//int Projectid = Convert.ToInt32(Session["ProjectId"]);
ProTrakEntities objEntity = new ProTrakEntities();
TextBox txtTitle = DetailsView1.FindControl("txtTask") as TextBox;
//RadComboBox cmbStatus = DetailsView1.FindControl("cmbStatus") as RadComboBox;
//var id = (from project in objEntity.Projects where project.ProjectId == Projectid select project).First();
RadComboBox cmbTaskType = DetailsView1.FindControl("cmbTasktype") as RadComboBox;
//RadComboBox cmbTaskPriorty = DetailsView1.FindControl("cmbPriority") as RadComboBox;
string Description = (DetailsView1.FindControl("RadEditor1") as RadEditor).Content;
var guid = (from g in objEntity.Projects where g.ProjectGuid == qString select g).First();
int pID = Convert.ToInt32(guid.ProjectId);
ProjectFeedback objResource = new ProjectFeedback();
objResource.ProjectId = pID;
objResource.Subject = txtTitle.Text;
objResource.Body = Description;
objResource.CreatedDate = Convert.ToDateTime(System.DateTime.Now.ToShortDateString());
objResource.FeedbackType = cmbTaskType.SelectedItem.Text;
objEntity.AddToProjectFeedbacks(objResource);
objEntity.SaveChanges();
DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
ClientScript.RegisterStartupScript(Page.GetType(), "mykey", "CloseAndRebind('navigateToInserted');", true);
}
}
Getting error at querystring statement-"Object reference not set to an instance of an object"
The query string is not inherited when you open a new page. You have to include the id in the URL, i.e. Upload.aspx?id=1752.
Edit:
A simple solution would be to just copy the search part of the page URL:
window.radopen("Upload.aspx" + document.location.search, "UserListDialog");
However, typically you would use the id value that you picked up from the query string in the server side code and generate client code to use it.
I am not sure but if I had to guess I would question whether the window object has been instantiated at the time you call radopen in the script section of your page. You should put a msgbox before the call window.radopen() call to print the contents of the window object if it is null that is your problem otherwise this will take more digging. Just my two cents.
I also noted that if the guid query returns no results the call to .First() will cause this error as well. Just another place to check while researching the issue.
There is one last place I see that could also throw this error if the objEntities failed to construct and returned a null reference then any call to the properties of the object will generate this error (i.e objEntitiey.Projects):
ProTrakEntities objEntity = new ProTrakEntities();
var guid = (from g in objEntity.Projects where g.ProjectGuid == qString select g).First();
This error is occurring because, as the other answerer said, you need to pass the ID to the RadWindow since the RadWindow doesn't know anything about the page that called it. You're getting a null reference exception because the window can't find the query string, so it's throwing an exception when you try to reference .ToString().
To get it to work, make your Javascript function like this:
function ShowAddFeedBackForm(Id) {
window.radopen(String.format("Upload.aspx?Id={0}", Id), "UserListDialog");
return false;
}
In the codebehind Page_Load event of your base page (ie, the page that is opening the window), put this:
if (!IsPostBack)
Button.OnClientClick = string.Format("javascript:return ShowAddFeedBackForm({0});", Request.QueryString["Id"]);
Of course, Button should be the ID of the button as it is on your page.

ASP.Net Control Visible=False Random Data Problem

Does anyone know of an issue with setting the Visible property of a control to false causing the value to change?
In the code below, the line:
control.Visible = dr.ParmDisplay;
On some servers, if the control is not visible it is not saving the value that was just set above it. We have a test server that this code works just fine, but we have a customer that the value is not saving. If the control is visible, it saves/shows/stores the value just fine on any server.
Is there some security patch that changes how this works??? I've Google'd it, and I don't find anything related to the visible property having this affect.
Here's the full code for this procedure:
protected void LoadReport()
{
dsReport.ReportParametersDataTable dt = objLoadXml.GetReportParameters(objReport.ReportName);
foreach (dsReport.ReportParametersRow dr in dt.Rows)
{
Control control = null;
IParm parameterControl = null;
if (dr.ParmType.ToUpper().StartsWith("DATERANGE"))
{
control = LoadControl("./UserControls/DateRange.ascx");
}
else if (dr.ParmType.ToUpper().StartsWith("DATE"))
{
control = LoadControl("./UserControls/Date.ascx");
}
else
{
control = LoadControl("./UserControls/Parameter.ascx");
}
control.EnableViewState = true;
parameterControl = (IParm)control;
parameterControl.ParmName = dr.ParmName;
parameterControl.ParmDescription = dr.ParmDescription;
parameterControl.ParmPickList = dr.ParmPickList.ToString();
if (dr["ParmDefaultValue"].ToString() != "")
parameterControl.ParmDefaultValue = dr.ParmDefaultValue;
control.Visible = dr.ParmDisplay;
PlaceHolder1.Controls.Add(control);
}
Thanks.
When you set a control to not visible, it does not get rendered to the browser. Therefore it will not be there on post back and the value won't make it back to the server.
If you need to persist the value w/out showing the control, store it directly in view state, or hidden input etc.

Programmatically add UserControl with events

I need to add multiple user controls to a panel for further editing of the contained data. My user control contains some panels, dropdown lists and input elements, which are populated in the user control's Page_Load event.
protected void Page_Load(object sender, EventArgs e)
{
// populate comparer ddl from enum
string[] enumNames = Enum.GetNames(typeof (SearchComparision));
var al = new ArrayList();
for (int i = 0; i < enumNames.Length; i++)
al.Add(new {Value = i, Name = enumNames[i]});
scOperatorSelection.DataValueField = "Value";
scOperatorSelection.DataTextField = "Name";
...
The data to be displayed is added to the user control as a Field, defined above Page_Load. The signature of the events is the following:
public delegate void ControlStateChanged(object sender, SearchCriteriaEventArgs eventArgs);
public event ControlStateChanged ItemUpdated;
public event ControlStateChanged ItemRemoved;
public event ControlStateChanged ItemAdded;
The update button on the user control triggers the following method:
protected void UpdateCriteria(object sender, EventArgs e)
{
var searchCritCtl = (SearchCriteria) sender;
var scEArgs = new SearchCriteriaEventArgs
{
TargetCriteria = searchCritCtl.CurrentCriteria.CriteriaId,
SearchComparision = ParseCurrentComparer(searchCritCtl.scOperatorSelection.SelectedValue),
SearchField = searchCritCtl.scFieldSelection.SelectedValue,
SearchValue = searchCritCtl.scFilterValue.Text,
ClickTarget = SearchCriteriaClickTarget.Update
};
if (ItemUpdated != null)
ItemUpdated(this, scEArgs);
}
The rendering page fetches the data objects from a storage backend and displays it in it's Page_Load event. This is the point where it starts getting tricky: i connect to the custom events!
int idIt = 0;
foreach (var item in _currentSearch.Items)
{
SearchCriteria sc = (SearchCriteria)LoadControl("~/content/controls/SearchCriteria.ascx");
sc.ID = "scDispCtl_" + idIt;
sc.ControlMode = SearchCriteriaMode.Display;
sc.CurrentCriteria = item;
sc.ItemUpdated += CriteriaUpdated;
sc.ItemRemoved += CriteriaRemoved;
pnlDisplayCrit.Controls.Add(sc);
idIt++;
}
When first rendering the page, everything is displayed fine, i get all my data. When i trigger an update event, the user control event is fired correctly, but all fields and controls of the user control are NULL. After a bit of research, i had to come to the conclusion that the event is fired before the controls are initialized...
Is there any way to prevent such behavior / to override the page lifecycle somehow? I cannot initialize the user controls in the page's Init-event, because i have to access the Session-Store (not initialized in Page_Init).
Any advice is welcome...
EDIT:
Since we hold all criteria informations in the storage backend (including the count of criteria) and that store uses the userid from the session, we cannot use Page_Init... just for clarification
EDIT #2:
I managed to get past some of the problems. Since i'm now using simple types, im able to bind all the data declaratively (using a repeater with a simple ItemTemplate). It is bound to the control, they are rendered in correct fashion. On Postback, all the data is rebound to the user control, data is available in the OnDataBinding and OnLoad events, everything looks fine.
But as soon it enters the real event (bound to the button control of the user control), all field values are lost somehow...
Does anybody know, how the page lifecycle continues to process the request after Databinding/Loading ? I'm going crazy about this issue...
Dynamic controls are can be a nightmare. The trick is to make sure you rebind everything on the postback.
I figured out a solution ;)
If i work with the OnCommand event on the buttons inside the usercontrol, i can pass a CommandArgument. Now im binding the collection identifier to the CommandArgument parameter of the button which enables me to handle all postbacks inside the usercontrol.
<asp:Button ID="scUpdate"
runat="server"
Text="Update"
OnCommand="HandleCommand"
CommandName="update"
CommandArgument='<%# CriteriaId %>' />
This declaration preserves the CriteriaId (a Guid) throughout postbacks and enables me to identify the modified entry on the underlying collection (managed on the page). The following code snippet shows how the event to the subscribing page is triggered.
scEArgs = new SearchCriteriaEventArgs
{
TargetCriteria = new Guid(e.CommandArgument.ToString()),
SearchComparision = ParseCurrentComparer(),
SearchField = scFieldSelection.SelectedValue,
SearchValue = scFilterValue.Text,
ClickTarget = SearchCriteriaClickTarget.Update
};
if (ItemUpdated != null)
ItemUpdated(this, scEArgs);
Maybe this answer helps somebody so i'll just post it ;)

Resources