ASP.net listview with state - c#

I have a dynamic list in ASP.net front end. User can click a button and add as many entries as it wants.
I'm using ViewState to save this data:
if(ViewState["items"] != null)
{
ListItems.DataSource = ViewState["items"];
}
ListItems.DataBind();
And there is a callback as follows:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
}
It's working fine, the problem is that, every time I add a new item, I loose any data I've entered in the other rows. How can I keep this information?
Edit:
I'm calling it from the .aspx page:
<asp:ListView ID="ListItems" class="block" SortExpression="DataType" ItemStyle-Wrap="false" runat="server">
<ItemTemplate >
<table>
<tr>
<asp:TextBox ID="Name" runat="server" class="inline" Text='<%# Eval("text") %>'></asp:TextBox>
</tr>
</table>
</ItemTemplate>
</asp:ListView>
Thanks in advance

Where are you calling this method? Are you calling in the same page? Before you construct the List you might be assigning to ListItems control.
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
ListItems.DataSource = ue;
ListItems.DataBind();
}
In this line, you can assign the collection to List and bind while adding in the ViewState.

There could be several points to check:
If you are assigning the values to ViewState on Page_Load then you might not be checking if it is a postback or not to overcome it you could just simply do the values assignment part to ListItems in an if condition: if(!Page.IsPostback){/* do stuff */ }
You might want to bind the ListItems each time you modify your list
You Could simply tweak with your code to see where the issue is nobody can help you investigate your code better than you!
Or finally, you may want to skip the ViewState at all, what you can do is:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue = (List<UserEntry>)ListItems.DataSource;
if(ue == null)
{
ue = new List<UserEntry>();
}
ue.Add(new UserEntry());
ListItems.DataSource = ue;
ListItems.DataBind();
} // Just an idea though

Related

I'm not able to store the value from the drop down

This is my code, when I run the code in the browser I'm not able to store value to the database I get from the drop down
I tried so many times but failed. Can anyone suggest a fix?
public partial class UserBranchAdminProfile : System.Web.UI.Page
{
public BLLCreateUser blbranchAdmin = new BLLCreateUser();
public Branch branchdetails = new Branch();
public BranchAdminDetails branchProfileDetails = new BranchAdminDetails();
}
protected void Page_Load(object sender, EventArgs e)
{
// if (!IsPostBack)
{
locationSelectDrop.DataSource = blbranchAdmin.getAllBranches();
locationSelectDrop.DataTextField = "BranchLocation";
locationSelectDrop.DataValueField = "BranchId";
locationSelectDrop.DataBind();
}
}
protected void submitProfileButton_Click(object sender, EventArgs e)
{
branchProfileDetails.userId = userIdText.Text;
branchProfileDetails.branchLocation=locationSelectDrop.SelectedValue.ToString();
branchProfileDetails.address = addressTextBox.Text;
branchProfileDetails.phoneNo = phoneNoText.Text;
branchProfileDetails.emailId = emailText.Text;
BLLCreateUser bc = new BLLCreateUser();
bool result = bc.insertBranchAdminProfileDetails(branchProfileDetails);
if (result == true)
{
branchAdminProfileLabel.Visible = true;
}
}
This is my html markup:
<td class="style1">
<asp:Label ID="locationSelect" runat="server" Text="Enter Location"/>
</td>
<td class="style2">
<asp:DropDownList ID="locationSelectDrop" runat="server" style="marginleft:0px"
Width="178px"></asp:DropDownList>
</td>
EDIT:
Are you actually even reading the value of locationSelectDrop in your BranchAdminDetails data object? :)
Every time when you click submit button, The Page_Load will call, and in your code for every post back load event filling your drop down again and setting selected value as 0th position. so un-comment the check of IsPostback in Page_Load event and try to debug again.

Why drop down list value is not passed?

I am filling DDL dynamically :
<asp:DropDownList ID="ddlTimeZone" Style="width: auto" runat="server" >
</asp:DropDownList>
With this function :
private void initTimeZone()
{
var timeZones = TimeZoneInfo.GetSystemTimeZones();
foreach (TimeZoneInfo timeZone in timeZones)
{
ListItem item = new ListItem()
{
Text = timeZone.DisplayName,
Value = timeZone.Id
};
ddlTimeZone.Items.Add(item);
}
}
Everything works fine but when I try to get the selected value I get an empty string
string item = ddlTimeZone.SelectedValue; -> empty string..
How can i solve this problem?
Because of the life cycle of controls in ASP.NET building a dynamic values will "disappear" in the PostBack process.
Try to call your initTimeZone method outside the if(!IsPostBack) condition and see if it works. like this:
protected void Page_Load(object sender,EventArgs e) {
if(!Page.IsPostBack) {
//Some Code
}
initTimeZone();
}
Check Control.EnableViewState for page or parent control. Maybe you turn it off?

Find and change a specific item in Repeater

I have the following <asp:Repeater>:
<asp:Repeater ID="repMenuParent" runat="server" DataSourceID="odsMenuParent" OnItemCommand="repMenuParent_OnItemCommand" OnItemDataBound="repMenuParent_OnItemDataBound" >
<ItemTemplate>
<asp:Button id="btnRepeaterParent" runat="server" SkinID="btnAgroquimicos" CssClass="celdasMenusDinamicas" Text='<%# Eval("NOMBRE") %>' CommandName='<%# Eval("NOMBRE") %>' />
</ItemTemplate>
</asp:Repeater>
When the commandEvent is triggered i set up a session with the commandName and the uniqueId:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Session.Add("nombreSubMenuAgro", e.CommandName);
String id = e.Item.UniqueID;
Session.Add("souceId", id);
}
The issue is the following: I need change the forecolor of the botton inside the repeater that is cicked by the user. In the beginnig all the buttons (items in the repeater) are gray. When someone is clicked I need to change the forecolor of it to red (like a bread crumb).
I've trying to find the item in the itemDataBound and compare the uniqueId but it doesn't work, i don't know how to find the specific item that is clicked to change the forecolor:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
String sessionID = "";
Button btnRepeater;
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
btnRepeater = (Button)e.Item.FindControl("btnRepeaterParent");
if (btnRepeater != null)
{
if(btnRepeater.UniqueID.Equals(sessionID))
{
btnRepeater.ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
}
I've read many blog's threads about repeater and find it's items, but can´t find any that solved my issue, Can help me please?
I think this problem is best solved with Javascript though I do have a server side solution for you.
The command event object has a property called CommandSource. This gives you access to the button that triggered the command event.
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Button btnRepeater=e.CommandSource;
btnRepeater.ForeColor = Drawing.Color.Red;
}
If you maintain a List of the IDs of the buttons pressed, then you can do the following:
First, change your button in the repeater to use CommandArgument not CommandName. Like so:
<asp:Button id="btnRepeaterParent" ... CommandArgument='<%# Eval("NOMBRE") %>' />
Create a page level property for accessing the list of IDs. Like so:
public List<string> ClickedIds
{
get
{
if(Session("ClickedIds") == null)
Session("ClickedIds") = new List<string>();
return (List<string>)Session("ClickedIds");
}
}
When one of your buttons in your repeater is clicked, handle it like so:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
this.ClickedIds.Add(e.CommandArgument);
}
Now, when you are binding the repeater in code-behind, check each button like so:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
//retrieve the id of the data item
//I am not sure of your data item structure, but it will be something to this effect
int nombre = e.Item.DataItem("NOMBRE");
if(this.ClickedIds.Contains(nombre))
{
((Button)e.Item.FindControl("btnRepeaterParent")).ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
DISCLAIMER:
I have not tested this code.

Dropdownlist SelectedIndexChanged firing on every postback

I am dynamically adding a custom user control to an update panel. My user control contains two dropdownlists and a textbox. When a control outside of the update panel triggers a postsback, I am re-adding the user control to the update panel.
The problem is...on postback when I re-add the user controls, it's firing the "SelectedIndexChanged" event of the dropdownlists inside the user control. Even if the selectedindex did not change since the last postback.
Any ideas?
I can post the code if necessary, but there's quite a bit in this particular scenario.
Thanks in advance!
EDIT...CODE ADDED BELOW
*.ASCX
<asp:DropDownList ID="ddlColumns" OnSelectedIndexChanged="ddlColumns_SelectedChanged" AppendDataBoundItems="true" AutoPostBack="true" runat="server">
*.ASCX.CS
List<dataColumnSpecs> dataColumns = new List<dataColumnSpecs>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
fillDDLColumns();
}
}
public void fillDataColumnsList()
{
dataColumns.Clear();
//COMMON GETDATATABLE RETURNS A DATA TABLE POPULATED WITH THE RESULTS FROM THE STORED PROC COMMAND
DataTable dt = common.getDataTable(storedProcs.SELECT_COLUMNS, new List<SqlParameter>());
foreach (DataRow dr in dt.Rows)
{
dataColumns.Add(new dataColumnSpecs(dr["columnName"].ToString(), dr["friendlyName"].ToString(), dr["dataType"].ToString(), (int)dr["dataSize"]));
}
}
public void fillDDLColumns()
{
fillDataColumnsList();
ddlColumns.Items.Clear();
foreach (dataColumnSpecs dcs in dataColumns)
{
ListItem li = new ListItem();
li.Text = dcs.friendlyName;
li.Value = dcs.columnName;
ddlColumns.Items.Add(li);
}
ddlColumns.Items.Insert(0, new ListItem(" -SELECT A COLUMN- ", ""));
ddlColumns.DataBind();
}
protected void ddlColumns_SelectedChanged(object sender, EventArgs e)
{
//THIS CODE IS BEING FIRED WHEN A BUTTON ON THE PARENT *.ASPX IS CLICKED
}
*.ASPX
<asp:UpdatePanel ID="upControls" runat="server">
<ContentTemplate>
<asp:Button ID="btnAddControl" runat="server" Text="+" OnClick="btnAddControl_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button ID="btnGo" runat="server" Text="Go" OnClick="btnGo_Click" ValidationGroup="vgGo" />
<asp:GridView...
*.ASPX.CS
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
uc_Counter = 0;
addControl();
gridview_DataBind();
}
else
{
reloadControls();
}
}
protected void btnGo_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
//THIS BUTTON CLICK IS WHAT'S TRIGGERING THE
//SELECTEDINDEXCHANGED EVENT TO FIRE ON MY *.ASCX
gridview_DataBind();
}
}
private void reloadControls()
{
int count = this.uc_Counter;
for (int i = 0; i < count; i++)
{
Control myUserControl = Page.LoadControl("~/Controls/myUserControl.ascx");
myUserControl.ID = "scID_" + i;
upControls.ContentTemplateContainer.Controls.AddAt(i, myUserControl);
((customUserControl)myUserControl).fillDDLColumns();
}
}
private void addControl()
{
Control myUserControl = Page.LoadControl("~/Controls/myUserControl.ascx");
myUserControl.ID = "scID_" + uc_Counter.ToString();
upControls.ContentTemplateContainer.Controls.AddAt(upControls.ContentTemplateContainer.Controls.IndexOf(btnAddControl), myUserControl);
//((customUserControl)myUserControl).fillDDLColumns();
this.uc_Counter++;
}
protected int uc_Counter
{
get { return (int)ViewState["uc_Counter"]; }
set { ViewState["uc_Counter"] = value; }
}
Even though this is already answered I want to put an answer here since I've recently tangled with this problem and I couldn't find an answer anywhere that helped me but I did find a solution after a lot of digging into the code.
For me, the reason why this was happening was due to someone overwriting PageStatePersister to change how the viewstate hidden field is rendered. Why do that? I found my answer here.
One of the greatest problems when trying to optimize an ASP.NET page to be more search engine friendly is the view state hidden field. Most search engines give more score to the content of the firsts[sic] thousands of bytes of the document so if your first 2 KB are view state junk your pages are penalized. So the goal here is to move the view state data as down as possible.
What the code I encountered did was blank out the __VIEWSTATE hidden fields and create a view_state hidden field towards the bottom of the page. The problem with this is that it totally mucked up the viewstate and I was getting dropdownlists reported as being changed when they weren't, as well as having all dropdownlists going through the same handler on submit. It was a mess. My solution was to turn off this custom persister on this page only so I wouldn't have to compensate for all this weirdness.
protected override PageStatePersister PageStatePersister
{
get
{
if (LoginRedirectUrl == "/the_page_in_question.aspx")
{
return new HiddenFieldPageStatePersister(Page);
}
return new CustomPageStatePersister(this);
}
}
This allowed me to have my proper viewstate for the page I needed it on but kept the SEO code for the rest of the site. Hope this helps someone.
I found my answer in this post .net DropDownList gets cleared after postback
I changed my counter that I was storing in the viewstate to a session variable.
Then I moved my reloadControls() function from the Page_Load of the *.ASPX to the Page_Init.
The key was dynamically adding my user control in the Page_Init so it would be a member of the page before the Viewstate was applied to controls on the page.

Find control in ListView EmptyDataTemplate

I have the a ListView like this
<asp:ListView ID="ListView1" runat="server">
<EmptyDataTemplate>
<asp:Literal ID="Literal1" runat="server" text="some text"/>
</EmptyDataTemplate>
...
</asp:ListView>
In Page_Load() I have the following:
Literal x = (Literal)ListView1.FindControl("Literal1");
x.Text = "other text";
but x returns null. I’d like to change the text of the Literal control but I don’t have no idea how to do it.
I believe that unless you call the DataBind method of your ListView somewhere in code behind, the ListView will never try to data bind. Then nothing will render and even the Literal control won’t be created.
In your Page_Load event try something like:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//ListView1.DataSource = ...
ListView1.DataBind();
//if you know its empty empty data template is the first parent control
// aka Controls[0]
Control c = ListView1.Controls[0].FindControl("Literal1");
if (c != null)
{
//this will atleast tell you if the control exists or not
}
}
}
You can use the following:
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.EmptyItem)
{
Control c = e.Item.FindControl("Literal1");
if (c != null)
{
//this will atleast tell you if the control exists or not
}
}
}
It's not specifically what you asked, but another way to do that kind of thing is like this:
<EmptyDataTemplate>
<%= Foobar() %>
</EmptyDataTemplate>
where Foobar is defined in your page's code behind file
public partial class MyClass : System.Web.UI.Page
{
...
public string Foobar()
{
return "whatever";
}
}
An alternative approach...
<asp:ListView ID="ListView1" runat="server">
<EmptyDataTemplate>
<asp:Literal ID="Literal1" runat="server" text="some text" OnInit="Literal1_Init" />
</EmptyDataTemplate>
...
</asp:ListView>
In code-behind...
protected void Literal1_Init(object sender, EventArgs e)
{
(sender as Literal).Text = "Some other text";
}
Protected Sub ListView1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs) Handles ListView1.ItemDataBound
Dim searchValue As String = Replace(Request.QueryString("s"), "", "'")
Dim searchLiteral2 As Literal = CType(ListView1.FindControl("Literal2"), Literal)
searchLiteral2.Text = "''" & searchValue & "''"
End Sub
...
Answering Broam's question "Is there any way to do this in the databound method? I'd rather not hardcode "controls[0]" as that's sloppy"
protected void ListView1_DataBound(object sender, EventArgs e)
{
ListView mylist = ((ListView)sender);
ListViewItem lvi = null;
if (mylist.Controls.Count == 1)
lvi = mylist.Controls[0] as ListViewItem;
if (lvi == null || lvi.ItemType != ListViewItemType.EmptyItem)
return;
Literal literal1 = (Literal)lvi.FindControl("Literal1");
if (literal1 != null)
literal1.Text = "No items to display";
}
Unfortunately, I've not found a way to not use Controls[0].
In the usual Item events (ItemDataBound or ItemCreate), you can use e.Item of the ListViewItemEventArgs to get the ListViewItem. In the DataBound event, there's only a generic EventArgs.
And on top of that, it seems that ((Control)sender).FindControl("Literal1") doesn't work either (find control from the listview at the top of the tree), hence the use of Controls[0] .FindControl(...) (find control from the listviewitem).

Categories

Resources