I have a page with a listview control and a datapager control. The listviews datasource is set programatically using this code:
Dim dal as new dalDataContext
Dim bookmarks = From data In dal.getData(userid)
listview1.DataSource = bookmarks
listview1.DataBind()
When i test this page in a browser it comes up with the error: 'ListView with id 'listview1' must have a data source that either implements ICollection or can perform data source paging if AllowPaging is true.'
How can i implement paging in this scenario?
Thanks
Try
listview1.DataSource = bookmarks.ToArray()
I had the same problem this week.
An answer to the click-twice problem that the OP subsequently encountered - move the Databind to the OnPreRender event handler:
protected void Page_PreRender(object sender, EventArgs e)
{
listview1.DataBind();
}
or maybe create a page properties changing and bindlistview there.
protected void lv_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{
//set current page startindex, max rows and rebind to false
DataPager dp = lvNews.FindControl("lvDataPager1") as DataPager;
dp.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
BindListView();
}
Related
i've tried to ask this question a number of ways. It's a difficult question to answer because you have to understand what's going on.
When do i fill a GridView?
The nieve answer is during Page_Load, if not a PostBack:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
The problem with that is that if it is a postback, the grid is not filled. The reason the grid is not filled is because we've turned off the viewstate of the grid.
So don't look at IsPostBack
We need to always fill the grid, postback or not:
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
The problem with that is that if the user sorts a column, the OnSorting event is called after both Page_Init and Page_Load:
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
DataSet ds = GetStuffToShow(e.SortExpression, e.SortDirection);
GridView1.DataSource = ds;
GridView1.DataBind();
}
we've run two database queries, when only one was required.
Cache is fine for column sorting
If i'm willing to accept invalid cache during column sorting, i can store the DataSet in the session variable, as long as i invalidate it for any other operation.
The problem is the OnSorting event is called after i need it (Page_Load):
protected void Page_Load(object sender, EventArgs e)
{
if (AGridViewOnSortingEventIsntBeingRaised)
{
DataSet ds = GetStuffToShow();
StoreTheDatasetInTheSessionSomehowInCaseTheyCallSortInTheFuture(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
DataSet ds = GetDataSetOutOfSessionSomehowThatDamnWellBetterBeThere();
SomehowSortAReadOnlyDisconnectedDataSet(ds, e.SortExpression, e.SortDirection);
GridView1.DataSource = ds;
GridView1.DataBind();
}
Fear of the unknown
Then there's still the terror i have because i turned off viewstate of the GridView. i don't think that a read-only asp:GridView should need tens of kilobytes base64 encoded, when i can just rebuild it from the server (or from memory).
But i believe that i am obligated to return the GridView to the state it was in the last time the page was rendered. And i have to do it before Page_Load (i.e. during Page_Init). i have this fear because someone said so. So i turn it into
protected void Page_Init(object sender, EventArgs e)
{
if (AGridViewOnSortingEventIsntBeingRaised)
{
DataSet ds = GetStuffToShow();
StoreTheDatasetInTheSessionSomehowInCaseTheyCallSortInTheFuture(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
The problem with this is that GetStuffToShow depends on things the user has typed into text boxes, which don't exist during Page_Init
Anyway, i'm rambling. It's too hot in here. Hopefully this question will be answered, unlike my other recent frustrations with asp.net
Bonus Reading
Sorting GridView Formed With Data Set
By adding a couple of hidden fields, one for the sort expression, and the other for the sort direction you can use those values to populate the GridView once at page load and then update the sorting in the Sorting event (sort code modified from the All-In-One Code Framework GridView sample):
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
// If the sorting column is the same as the previous one,
// then change the sort order.
if (SortExpression.Value.Equals(e.SortExpression))
{
SortDirection.Value = SortDirection.Value.Equals("ASC") ? "DESC" : "ASC";
}
// If sorting column is another column,
// then specify the sort order to "Ascending".
else
{
SortExpression.Value = e.SortExpression;
SortDirection.Value = "ASC";
}
var sortedView = new DataView(<convert your DataSet to a DataTable>)
{ Sort = string.Format("{0} {1}", this.SortExpression.Value, this.SortDirection.Value) };
GridView1.DataSource = sortedView;
GridView1.DataBind();
}
Note that SortDirection and SortExpression are the hidden fields. This also lends itself well to caching the DataSet.
Also, I wouldn't be concerned about the Page_Init issue that you brought up. That should only apply if you are dynamically creating your Controls.
A simple solution is to call Gridview.DataBind() on the Page.Pre_Render event, which makes it called after having handled any Button/Sorting, events. This a good way to ensure you call it only once per Request.
To make things clearer, it is also a good thing to access your dataset through a Property which will basically call your "Store-The-Dataset-In-The-Session-Somehow-In-Case-They-Call-Sort-In-The-Future" method in its Set part and your "Get-Data-Set-Out-Of-Session-That-Had-Better-Be-There" in the Get part.
You may try to fill the grid on Gridview Needdatasource event
it will be called when ever you perform a postback and get the proper functionality what ever you code in the event.
also if you want to bind it again you can just data databind method and that will call the needdatasource event again
I have a formview that on page load makes a call to a sql server and retrieves 5 records which I want the formview to paginate though.
I have sucessfully connected to the db, filled a dataset, and returned data when the web page renders. The problem is that when I move to a new page, the data does not change in the databound field.
Here is my code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
conn = new SqlConnection(connstr);
ds = new DataSet();
da = new SqlDataAdapter("call to stored proc", conn);
try
{
conn.Open();
da.Fill(ds, "m");
FormView1.DataSource = ds;
FormView1.DataKeyNames = new string[] { "PropKey" };
FormView1.DataBind();
}
catch (Exception ex)
{
Result = ex.Message;
}
finally
{
conn.Close();
}
}
Next when the paginate buttons are clicked I have this:
protected void FormView1_PageIndexChanging1(object sender, FormViewPageEventArgs e)
{
FormView1.PageIndex = e.NewPageIndex;
}
Please help,
Thanks
You will need to bind the data to the FormView just after setting the new page index like below.
protected void FormView1_PageIndexChanging1(object sender, FormViewPageEventArgs e)
{
FormView1.PageIndex = e.NewPageIndex;
BindFormViewData();
}
This is required because the FormView only displays the data for the active record and does not store any other records from the datasource, so upon change of the page index, the datasource is required to be bound again. See: Paging in a FormView Web Server Control
From the above link:
If the FormView control is bound to a data source control, or to any
data structure that implements the ICollection interface (including
datasets), the control gets all the records from the data source,
displays the record for the current page, and discards the rest. When
the user moves to another page, the FormView control repeats the
process, displaying a different record.
Hope this helps.
I have an htmlgeneric control and on run time i am adding control in it but when i click on any button then added controls disappear.
Dynamically created controls need to be created on every post back. You also need to give them an ID if you want to maintain and restore their ViewState.
For example, this will show the TextBox the first time the page is loaded, but on any subsiquent page loads, the control will be missing:
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
TextBox newControl = new TextBox()
{
ID = "newControl"
};
SomeControl.Controls.Add(newControl);
}
}
However, if you create the control on every postback with the same Id, then the control will be maintained with it's Text:
protected void Page_Init(object sender, EventArgs e)
{
TextBox newControl = new TextBox()
{
ID = "newControl"
};
SomeControl.Controls.Add(newControl);
}
Here's a good article about dealing with dynamic controls.
I'm using XmlDataSource as the datasource for a dropdownlist.
Now I want to set the SelectedValue of the drop down when the page initially loads. I have tried the OnDataBound event of the drop down in which I could see the total items. But setting the SelectedValue didn't work. InOnDataBinding event, I couldn't even see the total items probably because the list isn't bound yet?
How can I set the selected index based on a value?
This seems to work for me.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DropDownList1.DataBind(); // get the data into the list you can set it
DropDownList1.Items.FindByValue("SOMECREDITPROBLEMS").Selected = true;
}
}
DropDownList1.Items.FindByValue(stringValue).Selected = true;
should work.
This is working code
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DropDownList1.DataTextField = "user_name";
DropDownList1.DataValueField = "user_id";
DropDownList1.DataSource = getData();// get the data into the list you can set it
DropDownList1.DataBind();
DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf(DropDownList1.Items.FindByText("your default selected text"));
}
}
Have you tried, after calling DataBind on your DropDownList, to do something like ddl.SelectedIndex = 0 ?
I have several DropDownLists on a form which are dynamically populated as they move down the form pulling data from a DB. The data is all HTMLEncoded so I need to HTMLDecode the data to display the text.
I created a method to do this and trigger it 'ondatabound' for each DDL
ondatabound="SortHTMLModel"
BUT whats annoying I have the same method just changing the DDL name on each one. I want a generic single method each DDL could call. Here is the one for the DDL called ddlfuel
protected void SortHTML(object sender, EventArgs e)
{
foreach (ListItem item in ddlFuel.Items)
{
item.Text = Server.HtmlDecode(item.Text);
}
}
And one for the DDL called ddlModel
protected void SortHTMLModel(object sender, EventArgs e)
{
foreach (ListItem item in ddlModel.Items)
{
item.Text = Server.HtmlDecode(item.Text);
}
}
You see my predicament! So annoying I just can't figure out the syntax for one method
IIRC, the sender of an event is the actual control, so you could also say
protected void SortHTML(object sender, EventArgs e)
{
foreach (ListItem item in ((DropDownList)sender).Items)
{
item.Text = Server.HtmlDecode(item.Text);
}
}
and bind each DropDownList's DataBound event to SortHTML
Why can you not subclass the DropDownList control to do that before it renders the control? Then instead of using the stock DropDownList, you use your subclassed dropdownlist and the functionality happens automatically.