I have a problem whereby the viewstate of a repeater i.e. the controls within the repeater are not maintaing their viewstate.
I have the following:
Repeater 1:
<asp:Repeater ID="rptImages" runat="server">
<ItemTemplate>
<asp:LinkButton Text="Add" CommandName="Add" CommandArgument=<%# Eval("ID") %> runat="server" />
</ItemTemplate>
</asp:Repeater>
When the link button is clicked the value of the CommandArgument is stored in a hidden field on the page.
Upon postback I can't get the value of the hidden field until the prerender event handler has loaded. So in my prerender event I grab the value of the hidden field and store it in a List property, like so:
if (!string.IsNullOrEmpty(this.SelectedImageIDsInput.Text)) {
this.ImageList.Add(this.SelectedImageIDsInput.Text);
}
And the List property looks like so:
public List<string> ImageList {
get {
if (this.ViewState["ImageList"] == null) {
this.ViewState["ImageList"] = new List<string>();
}
return (List<string>)(this.ViewState["ImageList"]);
}
set { this.ViewState["ImageString"] = value; }
}
Once I have stored the value into my List property I bind my second repeater (again within the prerender event):
this.rptSelectedImages.DataSource = this.LightBoxControl.ImageList;
this.rptSelectedImages.DataBind();
The second repeater has a dropdownlist and a textbox within it. The problem is that the viewstate of these child controls is not maintained. I presume it is because with each postback I am rebinding the repeater, therefore it is rebuilt. What I don't know is how I can possibly get round this? The ImageList property is only updated upon a postback, so I obviously have to rebind the repeater with each postback - how else can it be done?
Any help would be greatly appreciated.
Thanks
Al
If you are rebinding the repeater, you need to do it on Init before the ViewState is loaded.
You should also check the IsPostback flag and only Bind the repeater when the page is not posted back.
To clarify if your second repeater is bound on PreRender then ViewState cannot be used to persist the controls, because they simply don't exist when ViewState is loaded - after Init, and before PreLoad.
You either need to continue binding on every postback, or store or list in Session so that you have access to the list to bind once on Init, (or on change).
I don't see the point of copying the CommandArgument property to a hidden field. What you should do is to use the ItemCommand event on the Repeater and use event bubbling. You can handle the Click event on you LinkButton like this:
repeater.ItemCommand += (sender, eventArgs) => {
var commandArgument = eventArgs.CommandArguments;
ImageList.Add(commandArgument);
rptSelectedImages.DataSource = ImageList;
rptSelectedImages.DataBind();
}
This should solve your problem.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Serialization;
namespace Repeater
{
public partial class WebForm1 : System.Web.UI.Page
{
private List<test> list = null;
protected void Page_Init(object sender, EventArgs e)
{
if (IsPostBack == false)
{
list = new List<test> { new test { Title = "aaaa" }, new test { Title = "bbb" } };
Repeater1.DataSource = list;
Repeater1.DataBind();
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void LoadViewState(object savedState)
{
if (savedState != null)
{
// Load State from the array of objects that was saved at ;
// SavedViewState.
object[] myState = (object[])savedState;
if (myState[0] != null)
{
list = Deserialize((string)myState[0]);
Repeater1.DataSource = list;
Repeater1.DataBind();
}
if (myState[1] != null)
base.LoadViewState(myState[1]);
}
}
protected override object SaveViewState()
{
object baseState = base.SaveViewState();
object[] allStates = new object[2];
allStates[1] = baseState;
allStates[0] = Serialize();
return allStates;
}
string Serialize()
{
var writer = new StringWriter();
var serializer = new XmlSerializer(typeof(List<test>));
serializer.Serialize(writer, list);
var xml = writer.ToString();
return xml;
}
List<test> Deserialize(string xml)
{
var serializer = new XmlSerializer(typeof(List<test>));
var deserializedBook = (List<test>)serializer.Deserialize(new StringReader(xml));
return deserializedBook;
}
}
public class test
{
public string Title { get; set; }
}
}
Related
I have a checkbox list that I want to populate and perhaps I could use the page_load and do the job from there, right?
protected void Page_Load(object sender, EventArgs e)
{
//...
var query = logic.GetPlanCoverages(planName);
cbl_MemberCoverages.DataSource = coverages;
cbl_MemberCoverages.DataBind();
}
But because Asp.Net has introduced Model Binding, now I can have this:
<asp:CheckBoxList runat="server" ID="cbl_MemberCoverages"
SelectMethod="BindMemberCoverages" DataTextField="CoverageName" DataValueField="CoverageCode">
</asp:CheckBoxList>
And in the code-behind:
public IEnumerable<PlanCoveragesDomainModel> BindMemberCoverages()
{
var planName = logic.GetShortPlanName();
var query = logic.GetPlanCoverages(planName);
return query;
}
BUT... There is something I still don't like in Model Binding, or perhaps it's just me that cannot work out how to use it properly when you have to prepopulate a form.
A typical scenario is when from a list of users, I want to edit one. I open a new page and I have this form with lots of fields to populate. Perhaps one of the users has already assigned some of these coverages. But at the moment, the only workaround I found is:
public IEnumerable<PlanCoveragesDomainModel> BindMemberCoverages([QueryString]string mode)
{
if (!"edit".Equals(mode, StringComparison.InvariantCultureIgnoreCase))
{
var planName = logic.GetShortPlanName();
var query = logic.GetPlanCoverages(planName);
return query;
}
var coverages = logic.GetPlanCoverages(CurrentModel.PlanName).Select(c => new ListItem(c.CoverageName, c.CoverageCode)).ToArray();
cbl_MemberCoverages.Items.AddRange(coverages);
cbl_MemberCoverages.DataSource = coverages;
cbl_MemberCoverages.DataBind();
foreach (ListItem listItem in cbl_MemberCoverages.Items)
{
listItem.Selected = CurrentModel.Coverages.Any(c => c.Value == listItem.Value);
}
return null;
}
Guys, any ideas?
Implement OnDataBound event for your CheckBoxList control.
<asp:CheckBoxList runat="server" ID="cbl_MemberCoverages"
SelectMethod="BindMemberCoverages" DataTextField="CoverageName"
DataValueField="CoverageCode"
OnDataBound="cblMemberCoverages_DataBound">
</asp:CheckBoxList>
Code
protected void cblMemberCoverages_DataBound(object sender, EventArgs e)
{
var chkBoxList = sender as CheckBoxList;
var item = chkbox.Items.FindByValue(queryStringCoverageCode);
if(item != null)
item.Selected = true;
}
I have two dropdown lists, one for days and one for nights. I also have two buttons, one button creates dynamic textboxes where the customer can enter what they want to do in day time and in place where they want to spend night.
e.g., if one customer selects 4 days and 4 nights, a textbox will be created on press of the first button.
When the user clicks the second button, I want to store all those values in database, but I noticed that on postback the fields are lost and I have no data to store.
How do I get the values from the controls created at runtime upon postback?
Here is how you can do it:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["testTextBox"] != null)
{
Request.Form[Session["testTextBox"].ToString()].ToString()
}
}
protected void Button1_Click(object sender, EventArgs e)
{
TextBox t = new TextBox { ID = "testTextBox" };
this.Form.Controls.Add(t);
Session["testTextBox"] = t.UniqueID;
}
If you are adding the textbox via a client side call you don't need to store the UniqueID. Button1_Click is the postback method for your button for example.
Even though adding controls in code behind is "fine", it can lead to trouble later. It also isn't very good when editing your view, and you have to change a bunch of code in code-behind. A solution is to use a data bound control, for instance a Repeater control. That way, you can design your view in your aspx file, and leave the coding to the cs-file. It also takes care of holding information when using postbacks, since it's already setup to use the viewstate of the controls, meaning you don't have to do it.
So, using a repeater, your aspx can look something like this.
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="RepeaterPage.aspx.cs" Inherits="ASPTest.RepeaterPage" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h1>Test</h1>
<div>
<asp:Button Text="Add textbox" ID="Button1" OnClick="OnAddItem" runat="server" />
<asp:Button Text="Read values" ID="Button2" OnClick="OnReadValues" runat="server" />
</div>
<div>
<asp:Label ID="values" runat="server"></asp:Label>
</div>
<asp:Repeater ID="listofvalues" runat="server">
<ItemTemplate>
<asp:HiddenField ID="ID" Value='<%# Eval("ID") %>' runat="server" />
<asp:TextBox ID="ValueBox" Text='<%# Server.HtmlEncode((string)Eval("Value")) %>' runat="server" />
</ItemTemplate>
</asp:Repeater>
</asp:Content>
Notice that I'm using a master page, so the Content control only links to some ContentPlaceHolder in the master page. In this aspx page, you'll see that the itemtemplate in the repeater control sets up all the design needed to show the values. We'll see how this pans out in the code.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ASPTest
{
public partial class RepeaterPage : Page
{
private List<Item> cache;
public List<Item> ItemValues
{
get
{
if (cache != null)
{
return cache;
}
// load values from database for instance
cache = Session["values"] as List<Item>;
if (cache != null)
{
return cache;
}
Session["values"] = cache = new List<Item>();
return cache;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
listofvalues.DataBinding += bindValues;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
DataBind();
}
}
protected void OnAddItem(object sender, EventArgs e)
{
ItemValues.Add(new Item("some value"));
DataBind();
}
protected void OnReadValues(object sender, EventArgs e)
{
foreach (RepeaterItem repeateritem in listofvalues.Items)
{
TextBox box = (TextBox)repeateritem.FindControl("ValueBox");
HiddenField idfield = (HiddenField)repeateritem.FindControl("ID");
Item item = findItem(idfield.Value);
item.Value = box.Text;
}
StringBuilder builder = new StringBuilder();
foreach (Item item in ItemValues)
{
builder.Append(item.Value).Append(";");
}
values.Text = builder.ToString();
}
private Item findItem(string idvalue)
{
Guid guid = new Guid(idvalue);
foreach (Item item in ItemValues)
{
if (item.ID == guid)
{
return item;
}
}
return null;
}
private void bindValues(object sender, EventArgs e)
{
listofvalues.DataSource = ItemValues;
}
}
public class Item
{
private readonly Guid id;
private string value;
public Item(string value)
{
this.value = value;
id = Guid.NewGuid();
}
public Guid ID
{
get { return id; }
}
public string Value
{
get { return value; }
set { this.value = value; }
}
}
}
Sorry about the long code example, but I wanted it to be thorough. You'll see that I introduced a list of Items, in the ItemValues property. You can load the values from wherever you want. I used the Session collection, but you can load from database or some other place if you want.
Also, notice how the only thing we know about the view is the control type and control ID. There's no code describing how controls should be added or styled, we leave that to the aspx page. This creates an easy separation of concerns between the two.
Instead, when we want to add a TextBox, we instead add a new instance of the data item, an instance of the Item class. In the OnReadValues method we can update the data items values bound to the repeater, and then use either the values from the controls or the values from the items in our data list.
I hope this illustrates how one can use ASP.NET to create dynamic pages, without creating the controls in code behind, because it's not really needed if you do it like this.
<asp:Button onclick="Some_event" Text="Add TextBox" ID="id1" runat="server" />
//once clicked:
<asp:TextBox ID="txt1" ......></asp:TextBox>
//when clicked again:
<asp:TextBox ID="txt1" ......></asp:TextBox>
<asp:TextBox ID="txt2" ......></asp:TextBox>
//and so on...
Is there a way to create dynamic controls which will persist even after the postback? In other words, when the user clicks on the button, a new textbox will be generated and when clicks again the first one will remain while a second one will be generated. How can I do this using asp.net ? I know that if I can create the controls in the page_init event then they will persist but I dont know if it possible to handle a button click before the page_init occurs, therefore there must be another way.
Yes, this is possible. One way to do this using purely ASP.NET (which seems like what you're asking for) would be to keep a count of the TextBox controls that you have added (storing that value in the ViewState) and recreate the TextBox controls in the Page_Load event. Of course, nowadays most people would probably use Javascript or jQuery to handle this task client side, but I put together a quick example to demonstrate how it works with postbacks:
Front page:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="DynamicControls.aspx.cs" Inherits="MyAspnetApp.DynamicControls" EnableViewState="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"></head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAddTextBox" runat="server" Text="Add" OnClick="btnAddTextBox_Click" />
<asp:Button ID="btnWriteValues" runat="server" Text="Write" OnClick="btnWriteValues_Click" />
<asp:PlaceHolder ID="phControls" runat="server" />
</div>
</form>
</body>
</html>
Code behind:
using System;
using System.Web.UI.WebControls;
namespace MyAspnetApp
{
public partial class DynamicControls : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Recreate textbox controls
if(Page.IsPostBack)
{
for (var i = 0; i < TextBoxCount; i++)
AddTextBox(i);
}
}
private int TextBoxCount
{
get
{
var count = ViewState["txtBoxCount"];
return (count == null) ? 0 : (int) count;
}
set { ViewState["txtBoxCount"] = value; }
}
private void AddTextBox(int index)
{
var txt = new TextBox {ID = string.Concat("txtDynamic", index)};
txt.Style.Add("display", "block");
phControls.Controls.Add(txt);
}
protected void btnAddTextBox_Click(object sender, EventArgs e)
{
AddTextBox(TextBoxCount);
TextBoxCount++;
}
protected void btnWriteValues_Click(object sender, EventArgs e)
{
foreach(var control in phControls.Controls)
{
var textBox = control as TextBox;
if (textBox == null) continue;
Response.Write(string.Concat(textBox.Text, "<br />"));
}
}
}
}
Since you are recreating the controls on each postback, the values entered into the textboxes will be persisted across each postback. I added btnWriteValues_Click to quickly demonstrate how to read the values out of the textboxes.
EDIT
I updated the example to add a Panel containing a TextBox and a Remove Button. The trick here is that the Remove button does not delete the container Panel, it merely makes it not Visible. This is done so that all of the control IDs remain the same, so the data entered stays with each TextBox. If we were to remove the TextBox entirely, the data after the TextBox that was removed would shift down one TextBox on the next postback (just to explain this a little more clearly, if we have txt1, txt2 and txt3, and we remove txt2, on the next postback we'll create two textboxes, txt1 and txt2, and the value that was in txt3 would be lost).
public partial class DynamicControls : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
for (var i = 0; i < TextBoxCount; i++)
AddTextBox(i);
}
}
protected void btnAddTextBox_Click(object sender, EventArgs e)
{
AddTextBox(TextBoxCount);
TextBoxCount++;
}
protected void btnWriteValues_Click(object sender, EventArgs e)
{
foreach(var control in phControls.Controls)
{
var panel = control as Panel;
if (panel == null || !panel.Visible) continue;
foreach (var control2 in panel.Controls)
{
var textBox = control2 as TextBox;
if (textBox == null) continue;
Response.Write(string.Concat(textBox.Text, "<br />"));
}
}
}
private int TextBoxCount
{
get
{
var count = ViewState["txtBoxCount"];
return (count == null) ? 0 : (int) count;
}
set { ViewState["txtBoxCount"] = value; }
}
private void AddTextBox(int index)
{
var panel = new Panel();
panel.Controls.Add(new TextBox {ID = string.Concat("txtDynamic", index)});
var btn = new Button { Text="Remove" };
btn.Click += btnRemove_Click;
panel.Controls.Add(btn);
phControls.Controls.Add(panel);
}
private void btnRemove_Click(object sender, EventArgs e)
{
var btnRemove = sender as Button;
if (btnRemove == null) return;
btnRemove.Parent.Visible = false;
}
}
I read an article by Scott Mitchell that explains that ViewState only persists changed control state across post-back, and not the actual controls themselves. I did not have your exact scenario, but a project I was working on required dynamically added user controls and I had to add them on every postback. In that case, it is still useful to create them in Init so that they can retain their state. Here is the link: Understanding ASP.NET View State. Check section “View State and Dynamically Added Controls”.
You may have to keep track of all the controls that you are adding (in session state for example) and re-create them on post back. I just did a small test where I keep a List<string> of all the Textbox ids in Session. On postback, I recreate all the textboxes.
I have to set a LinkButton's OnClientClick attribute but I don't know what this value is until the LinkButton is bound to. I'm trying to set the value when the repeater binds, but I can't workout how to get the 'boundItem/dataContext' value...
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:LinkButton Text="HelloWorld" ID="Hyper1" runat="server" OnDataBinding="Repeater1_DataBinding" >
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
{
var list = new List<TestObject>();
list.Add(new TestObject() {TestValue = "testing1"});
list.Add(new TestObject() { TestValue = "testing2" });
list.Add(new TestObject() { TestValue = "testing3" });
this.Repeater1.DataSource = list;
this.Repeater1.DataBind();
}
public void Repeater1_DataBinding(object sender, EventArgs e)
{
var link = sender as HyperLink;
//link.DataItem ???
}
Is there anyway to find out what the current rows bound item is?
Maybe you need to use ItemDataBound event. It provides RepeaterItemEventArgs argument which has DataItem available
this.Repeater1.ItemDataBound += Repeater1_ItemDataBound;
void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var dataItem = e.Item.DataItem;
}
I assume you are trying to get the value for the row that is currently being databound?
You can change your function to:
public void Repeater1_DataBinding(object sender, EventArgs e)
{
var link = sender as HyperLink;
string valueYouWant = Eval("TestValue").ToString();
// You could then assign the HyperLink control to whatever you need
link.Target = string.Format("yourpage.aspx?id={0}", valueYouWant);
}
valueYouWant now has the value of the field TestValue for the current row that is being databound. Using the DataBinding event is the best way to do this compared to the ItemDataBound because you don't have to search for a control and localize the code specifically to a control instead of a whole template.
The MSDN library had this as a sample event handler:
public void BindData(object sender, EventArgs e)
{
Literal l = (Literal) sender;
DataGridItem container = (DataGridItem) l.NamingContainer;
l.Text = ((DataRowView) container.DataItem)[column].ToString();
}
(see http://msdn.microsoft.com/en-us/library/system.web.ui.control.databinding.aspx)
As you can see it is a simple demonstration of how to access the data item and get data from it. Adapting this to your scenario is an exercise left to the reader. :)
I have a repeater control with a check box, if I check the box then my delete functionality will delete an item in the underlying table.
When I test the delete functionality on an aspx page with a code behind page, everything works fine. Hooray!
However, when I take the repeater and put it into a User Control, the delete functionality thinks that my repeater control has no items.
Code as below, I've tried to strip out the unnecessary code. I asked this question on the asp.net forums but no-one responded!
asxc:
<%# Control AutoEventWireup="true" Inherits="Moto.Web.UI.UserControls.Messages.MessageListForm" Language="C#" %>
<asp:button id="btnDelete" runat="server" text="Delete" OnClick="btnDelete_Click" ></asp:button>
<asp:Repeater ID="RepeaterMessageList" runat="server" EnableViewState="true" >
<ItemTemplate >
<div class="messageContainer item" >
<div class="messageListLeft">
<div class="messageList">
<asp:Image ID="imgUser" runat="server" CssClass="" />
<asp:CheckBox ID="chkDeleteMe" runat="server" Text="test" />
</div>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
Code file:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace Moto.Web.UI.UserControls.Messages
{
public class MessageListForm : Moto.Web.UI.UserControls.UserControl//System.Web.UI.UserControl
{
private string userGUID;
private MembershipUser MembershipUser;
private Moto.Business.UserComponent userComponent;
private Moto.Business.User user;
private Button cmdPrev;
private Button cmdNext;
private Button cmdNewest;
private Button cmdOldest;
private Label lblCurrentPage;
private Label lblMessage;
private HyperLink hypPageRedirect;
private Repeater RepeaterMessageList;
private MessageView DisplayMessages = MessageView.Inbox;//default setting
private Button btnDelete;
private Label lblConfirmDelete;
protected Button btnConfirmDelete;
protected Button btnCancelDelete;
enum MessageView
{
Inbox, //0
Sent //1
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.InitializePage();
}
protected void InitializePage()
{
this.cmdNext = (Button)FindControl("cmdNext");
this.cmdPrev = (Button)FindControl("cmdPrev");
this.cmdOldest = (Button)FindControl("cmdOldest");
this.cmdNewest = (Button)FindControl("cmdNewest");
this.lblCurrentPage = (Label)FindControl("lblCurrentPage");
// this.RepeaterMessageList = (Repeater)FindControl("RepeaterMessageList");
this.RepeaterMessageList = (Repeater)FindControlRecursive(this, "RepeaterMessageList");
this.hypPageRedirect = (HyperLink)FindControl("hypPageRedirect");
this.lblMessage = (Label)FindControl("lblMessage");
//delete functionality
this.btnDelete = (Button)FindControl("btnDelete");
this.lblConfirmDelete = (Label)FindControl("lblConfirmDelete");
this.btnConfirmDelete = (Button)FindControl("btnConfirmDelete");
this.btnCancelDelete = (Button)FindControl("btnCancelDelete");
//where are we coming from - are we the Logged in user or just a voyeur?
if (Page.User.Identity.IsAuthenticated)
{
this.userComponent = new Moto.Business.UserComponent();
this.MembershipUser = Membership.GetUser();//user logged in
this.userGUID = this.MembershipUser.ProviderUserKey.ToString();//signed in user
this.user = this.userComponent.GetByUserGUID(this.userGUID);
}
else
{
Response.Redirect("~/default.aspx");
}
if (null != this.Page.Request.QueryString["viewing"])
{
//reset the enum value
DisplayMessages = this.Page.Request.QueryString["viewing"].ToLower() == "sent" ? MessageView.Sent : MessageView.Inbox;
CurrentPage = 0;//if it's a redirect then reset the Current Page
}
}
void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ItemsGet();//on post back we'll call it elsewhere
}
switch (DisplayMessages)
{
case MessageView.Sent:
this.hypPageRedirect.Text += "Inbox";
this.hypPageRedirect.NavigateUrl += "?viewing=Inbox";
break;
case MessageView.Inbox:
this.hypPageRedirect.Text += "Sent Items";
this.hypPageRedirect.NavigateUrl += "?viewing=Sent";
break;
}
}
protected void cmdPrev_Click(object sender, EventArgs e)
{
// Set viewstate variable to the previous page
CurrentPage -= 1;
// Reload control
ItemsGet();
}
protected void cmdNext_Click(object sender, EventArgs e)
{
// Set viewstate variable to the next page
CurrentPage += 1;
// Reload control
ItemsGet();
}
protected void cmdNewest_Click(object sender, EventArgs e)
{
// Set viewstate variable to the previous page
CurrentPage = 0;
// Reload control
ItemsGet();
}
protected void cmdOldest_Click(object sender, EventArgs e)
{
}
public void RepeaterMessageList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// Execute the following logic for Items and Alternating Items.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
//Are we vieing the Inbox or Sent items?
if (DisplayMessages == MessageView.Inbox)
{
.........Do stuff
}
else
{
.........Do stuff
}
}
}
private void ItemsGet()
{
// this.RepeaterMessageList = (Repeater)FindControl("RepeaterMessageList");
this.RepeaterMessageList.ItemDataBound += new RepeaterItemEventHandler(RepeaterMessageList_ItemDataBound);
// Populate the repeater control with the Items DataSet
PagedDataSource objPds = new PagedDataSource();
if (DisplayMessages == MessageView.Inbox)//which table are we getting data from?
{
List<Moto.Business.MessageReceived> messages;
Moto.Business.MessageReceivedComponent messageComponent =
new Moto.Business.MessageReceivedComponent();
messages = messageComponent.GetByReceiverGUID(this.user.UserGUID);
objPds.DataSource = messages;
}
else
{
List<Moto.Business.MessageSent> messages;
Moto.Business.MessageSentComponent messageComponent =
new Moto.Business.MessageSentComponent();
messages = messageComponent.GetBySenderGUID(this.user.UserGUID);
objPds.DataSource = messages; //Items.Tables[0].DefaultView;
}
// Indicate that the data should be paged
objPds.AllowPaging = true;
// Set the number of items you wish to display per page
objPds.PageSize = 25;
// Set the PagedDataSource's current page
objPds.CurrentPageIndex = CurrentPage;
this.lblCurrentPage.Text = "Page " + (CurrentPage + 1).ToString() + " of "
+ objPds.PageCount.ToString();
// Disable Prev or Next buttons if necessary
this.cmdPrev.Enabled = !objPds.IsFirstPage;
this.cmdNext.Enabled = !objPds.IsLastPage;
this.cmdOldest.Enabled = !objPds.IsLastPage;
this.cmdNewest.Enabled = !objPds.IsFirstPage;
this.RepeaterMessageList.DataSource = objPds;
this.RepeaterMessageList.DataBind();
}
public int CurrentPage
{
get
{
// look for current page in ViewState
object o = this.ViewState["_messagesCurrentPage"];
if (o == null)
return 0; // default page index of 0
else
return (int)o;
}
set
{
this.ViewState["_messagesCurrentPage"] = value;
}
}
protected void btnDelete_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in this.RepeaterMessageList.Items)
{
CheckBox chkDeleteMe = item.FindControl("chkDeleteMe") as CheckBox;
TextBox test = item.FindControl("test") as TextBox;
if (chkDeleteMe.Checked)
{
if (DisplayMessages == MessageView.Inbox)//which table are we getting data from?
{
.........Do stuff
}
else
{
.........Do stuff
}
}
}
// Reload control
ItemsGet();
}
protected Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
}
Any help greatly appreciated!
I think the problem is that when the delete button is clicked the Page_Load is fired again and since its a postback it does not execute the ItemsGet method and hence the repeater does not have the data.
Try putting the ItemsGet method call in the OnPreRender event instead of Page_Load.
Jomit
The Delete event fires but in the fornext...loop the repeater thinks it has no items.
After looping it then calls the ItemsGet() Method which returns all data from the table.
So it binds to the repeater and displays all the items correctly but when repeating through the list of items on postback nothing is found?
Is the delete event definately being fired? What is visible after you have hit the delete button? (e.g. is the table empty or does it still display all the items)
Update:
Comment out the GetItems method and see if the table is empty or not on postback. It sounds like your repeaters viewstate isn't populating the control again or something.
Try to move the InitializePage() method to another place. I don´t know why, but I had the same problem and the problem was when I try to access some controls in the OnInit event. I moved to event OnPreLoad() and works.
I hope to help you...
The PreRender solution also worked in our case, where we had such code in two pages of our application. This was working perfect in .Net 1.1 but however broke when we ported this code to .Net 2.0.
Not sure why it broke without any major changes to codebase.
Thanks for the OnPreRender tip!
-Ghanshyam