C# session not saving while creating webforms - c#

my area of programming expertise isn't web programming however I'm currently expanding my knowledge by studying C#.net webforms and I am working on an example.
I have a button which has this code:
protected void Button1_Click(object sender, EventArgs e)
{
Course course = new Course(txtId.Text, txtName.Text, txtDesc.Text);
// This line checks to see if I already have a course manager
cm = (courseManager)Session["CourseManager"];
// If I do not have a course manager, it will create one for me.
if (cm == null)
{
cm = new courseManager();
}
// This will add a course to my list of courses
cm.addCourse(course);
// This will make sure that my web page can see the list of courses.
Session.Add("CourseManager", cm);
// This will reset my text boxes
txtId.Text = "";
txtName.Text = "";
txtDesc.Text = "";
// This will print course to page
//lblId.Text = course.getId();
//lblName.Text = course.getName();
//lblDesc.Text = course.getDesc();
}
and then on the webform I have this:
<table id="courses">
<%
if (cm != null)
{
for (int i = 0; i < cm.getCourses().Count(); i++)
{
string id = cm.getCourses().ElementAtOrDefault(i).getId();
string name = cm.getCourses().ElementAtOrDefault(i).getName();
string desc = cm.getCourses().ElementAtOrDefault(i).getDesc();
%>
<tr>
<td><%=id %></td>
<td><%=name %></td>
<td><%=desc %></td>
</tr>
<%
}
}
%>
</table>
I am told this is all I need to get an active session going however the session doesn't seem to be saving the courseManager class to the session and it keeps creating new instances of the coursemanager class. Am I missing something that c#.net webforms need to keep items in a session?
regards,
Joey

Related

How to store/restore table with dynamic elements in view state in c# asp web aplication

I am new to concept of web app with dynamic content.
I am creating simple app that take information (steps for a test) from database and adds rows to table (every row is containing, two labels, two radio buttons and text field).
It works like this:
1. I have a page with text box and button,
2. I put test ID to retrieve test steps, then click submit button
3. Based on number of steps I add a row to table for every step, so I have table that looks like this:
[Label.text="Step1"][RadioButtonPass][RadioButtonFail][Label.Text="Comment:"][TextBox]
[Label.text="Step2"][RadioButtonPass][RadioButtonFail][Label.Text="Comment:"][TextBox]
[Label.text="Step3"][RadioButtonPass][RadioButtonFail][Label.Text="Comment:"][TextBox]
etc.
When user press every radio button he can click submitResult button and data are send to db.
Page is genereting correctly but I am having trouble with dynamic content because when I hit submitResult button table is empty again (at this point submitResult button do nothing). I read about it and I think I need to store table into View State. How can I do it?
I tried to save table to
ViewState[table.ID] = table;
at the end of PopulateTable method and then restore it in
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
if (ViewState[TableForMethods.ID] != null)
{
TableForMethods = (Table)ViewState[TableForMethods.ID];
}
}
}
but that doesn't work.
My code looks like this:
*.aspx
<body style="height: 510px">
<form id="form1" runat="server">
<p>
Put test case ID and submit
</p>
<asp:TextBox ID="TextBoxId" runat="server">1804673290</asp:TextBox>
<asp:Button ID="ButtonRetriveId" runat="server" OnClick="ButtonSubmitId_Click" Text="Submit" Width="81px" />
<p>
</p>
<p>
<asp:Label ID="LabelMethods" runat="server"></asp:Label>
</p>
<p>
<asp:Table ID="TableForMethods" runat="server">
</asp:Table>
</p>
<div style="text-align: right">
<asp:Button ID="ButtonSubmitResults" runat="server" Text="Submit result" OnClick="ButtonSubmitResults_Click" Visible="False" />
</div>
<div style="text-align: right; position: absolute; bottom: 0px">
<asp:Label ID="LabelStatus" runat="server"></asp:Label>
</div>
</form>
<script>
var trPassArray = $("tr input[id*='RadioButtonPass']").click(function () {
this.closest("tr").setAttribute("bgcolor", "yellowgreen");
console.log("zmien na green");
console.log(closest("tr"));
});
var trFailArray = $("tr input[id*='RadioButtonFail']").click(function() {
this.closest("tr").setAttribute("bgcolor", "orangered");
console.log("zmien na red");
console.log(this.closest("tr"));
});
console.log(trPassArray);
console.log(trFailArray);
</script>
</body>
*.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ButtonSubmitId_Click(object sender, EventArgs e)
{
this.PopulateTable(TableForMethods, value);
ButtonSubmitResults.Visible = true;
}
protected void ButtonSubmitResults_Click(object sender, EventArgs e)
{
}
private void PopulateTable(Table table, string value)
{
string[] sep = { "<br>" };
var words = value.Split(sep, StringSplitOptions.RemoveEmptyEntries);
for (int iterator = 1; iterator <= words.Count(); iterator++)
{
var tRow = new TableRow { ID = "Row" + iterator };
table.Rows.Add(tRow);
var tCell = new TableCell();
var myLabel = new Label
{
Text = words[iterator - 1],
ID = "Label " + iterator
};
var radiobuttonPass = new RadioButton
{
Text = "Pass ",
ID = "RadioButtonPass " + iterator,
GroupName = "passFailGroup" + iterator,
};
radiobuttonPass.CheckedChanged += passRadioButton_CheckedChanged;
var radiobuttonFail = new RadioButton
{
Text = "Fail ",
ID = "RadioButtonFail " + iterator,
GroupName = "passFailGroup" + iterator,
};
radiobuttonFail.CheckedChanged += failRadioButton_CheckedChanged;
var upPassFail = new UpdatePanel { UpdateMode = UpdatePanelUpdateMode.Conditional };
upPassFail.ContentTemplateContainer.Controls.Add(radiobuttonPass);
upPassFail.ContentTemplateContainer.Controls.Add(radiobuttonFail);
var passTrigger = new AsyncPostBackTrigger
{
ControlID = radiobuttonPass.ID,
EventName = "CheckedChanged"
};
upPassFail.Triggers.Add(passTrigger);
var failTrigger = new AsyncPostBackTrigger
{
ControlID = radiobuttonFail.ID,
EventName = "CheckedChanged"
};
upPassFail.Triggers.Add(failTrigger);
var labelComment = new Label
{
Text = " Comment:",
ID = "LabelComment " + iterator.ToString()
};
TextBox textBoxComment = new TextBox { ID = "TextBoxComment " + iterator.ToString() };
tCell.Controls.Add(myLabel);
tCell.Controls.Add(radiobuttonPass);
tCell.Controls.Add(radiobuttonFail);
tCell.Controls.Add(labelComment);
tCell.Controls.Add(textBoxComment);
tRow.Cells.Add(tCell);
}
}
What you're trying to do won't work. ViewState is used by the server application to store information between requests.
During the course of page load or a postback the server modifies the state of the page or its controls
When you post back, without some way to "remember" what was done, all of those changes would be lost. It would be like loading the page for the first time again.
ASP.NET solves this by writing details about the controls in a form field (ViewState.) That way every time there's postback you're sending data back to the server telling it what the state of the page and controls are, so it can recreate it.
You're making changes to the HTML on the client. At that point the page has been rendered, including ViewState. It only keeps track of the server's changes, not anything that happens on the client. So the server will never know that those changes happened.
There are a few ways to solve this (more than two, but these are the obvious ones.)
Whatever changes have to happen to modify that table, do it on the server. If the user interacts with something, do a postback to the server. The server modifies the table, and assuming that ViewState is enabled for the table, those changes are already written to ViewState and persisted.
Avoid postbacks. If there aren't server controls then after the page loads it behaves just like a normal HTML page, and you can do whatever you want on the client.
This gets a little messy: store client-side changes on the client. When you update the table on the client then you could store it in localStorage. When the page refreshes you could then have a client script that checks localStorage and restores whatever client-side stuff you stored there. Think of it as just like ViewState, but the opposite. ViewState stores server-side data between roundtrips. localStorage stores client-side data between roundtrips. The catch is that maybe on some postback you'll completely change the table (like new data, something else) and you'll have to have a way to distinguish that so that in that scenario you don't refresh it from localStorage.
Mixing WebForms with client-side code can be a little frustrating. We start learning about all of these neat client-side tools, but they don't always play well with the behavior of WebForms. Client-side code wants to change things on the page. WebForms wants to refresh the whole page.
Personally I would go with option one or two if possible vs trying to cross-breed the behavior of the two.

How to loop through the div to reset the delegate of the links in?

If i have method like this to Draw my side Menu Dynamically :
private void DrawSideMenu()
{
LinkButton x;
TaskDTO TaskList = new TaskDTO();
List<TaskDTO> List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
HtmlGenericControl myDIV = new HtmlGenericControl("div");
myDIV.ID = "menu8";
HtmlGenericControl myOrderedList = new HtmlGenericControl("ul");//css clss for <ul>
myOrderedList.ID = "orderedList";
myOrderedList.Attributes.Add("class", "task");
HtmlGenericControl listItem1;
string count = "";
foreach (TaskDTO i in List)
{
count = AdjustMenuCount1(i.TaskCode);
x = new LinkButton();
x.ID = i.TaskCode.ToString();
x.Text = i.TaskName + " " + count;
x.Click += new EventHandler(TaskC);
x.Style["FONT-FAMILY"] = "tahoma";
listItem1 = new HtmlGenericControl("li");
listItem1.Attributes.Add("class", "normal");
if (count != "0")
{
listItem1.Controls.Add(x);
myOrderedList.Controls.Add(listItem1);
}
}
myDIV.Controls.Add(myOrderedList);
MenuTD.Controls.Add(myDIV);
Session["SideMenu"] = myDIV;//Save to redraw when page postbacks
}
This Method takes long time to draw my menu.so i call it one time in (!IsPostBack) and save it in session so that i could redraw it like that :
MenuTD.Controls.Add( ((System.Web.UI.Control)(Session["SideMenu"])));
It redraws it successfully but when i click on any link it doesn't hit the event because i thought it's not possible to save the x.Click += new EventHandler(TaskC); in the session ,so i want to know how to loop through my session content to resetting the delegate of my link ?
That idea won't work because if you're not wiring up the Event Handler every time the page is loaded, it won't run.
If we come back to the original issue, you said it's slow. Creating controls at runtime cannot be slow and it's most likely the way you create your list of items:
List<TaskDTO> List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
Instead of storing complete menu, try to store in the Session only List and create all controls as usual. If menu is required on one page only, then use ViewState instead of Session.
Also it makes sense to change the entire code as currently you hardcode all style and layout settings in the code. Create all layout (div, ul, li) in aspx, move all styles in css (for example, you use "task" class but still set "tahoma" in the code). This would simplify the code and bring more flexibility.
List<TaskDTO> List = null;
void Page_Load(object sender, EventArgs e)
{
if (ViewState["List"] != null) {
List = (List<TaskDTO>)ViewState["List"];
} else {
// ArrayList isn't in view state, so we need to load it from scratch.
List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
}
// Code to create menu, e.g.
if (!Page.IsPosBack) {
Repeater1.DataSource = List;
Repeater1.DataBind();
}
}
void Page_PreRender(object sender, EventArgs e)
{
// Save PageArrayList before the page is rendered.
ViewState.Add("List", List);
}
...
<ul id="orderedList">
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<li><%# Eval("TaskName") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
Maybe save it in application level so it only gets built once, then just put the menu into an object and loop through it to re-add the clicks.
I'm afraid that in order for it to work you are going to have to rebind the Click handler on every Page_Load.
Based on your code, and assuming your TaskC is available, you can make this method:
private void RebindMenuHandlers() {
if(Session["SideMenu"] == null)
return; // Your menu has not been built yet
var menu = ((System.Web.UI.Control)(Session["SideMenu"]));
var orderedList = menu.Controls[0];
foreach(var listItem in orderedList){
foreach(var control in listItem){
var linkButton = control as LinkButton;
if(linkButton != null){
linkButton.Click += new EventHandler(TaskC);
}
}
}
}
Then call it on your Page_Load event:
void Page_Load(object sender, EventArgs e)
{
RebindMenuHandlers();
// .... etc
}
I just typed this directly here, so please forgive any silly compilation mistakes, this should be enough to give you the general idea. Hope that helps.

Get value of droplink in Code-Behind

I am trying to get the display name of an item in a droplink in the back-end C# code. I am using Sitecore 6.6, not using MVC, and am setting a droplink control in the CMS for clients called Address. The droplink source goes to /sitecore/Templates/User Defined/WAC/Address, and the individual items have an SEO-compliant name and a readable display name.
For example:
Item ID: {9E60F5F8-FBF2-4CBD-BB13-6A93397AAC87}
Name: 100-main-street
Display Name: 100 Main Street, Sample Town, 10011
My code:
protected void Page_Load(object sender, EventArgs e)
{
String sl = "";
Sitecore.Data.Items.Item currentItem = Sitecore.Context.Item;
// BEGIN main class list
Sitecore.Collections.ChildList classList = currentItem.Children;
foreach (Sitecore.Data.Items.Item mainPage in classList)
{
if (mainPage.TemplateID.ToString() == "{27A9692F-AE94-4507-8714-5BBBE1DB88FC}")
{
sl += "<span class=\"address\">" + mainPage.Fields["Address"] +"</span>";
}
else
{
}
}
// END main class list
classSessionList.Text = sl;
}
This code will give me the ID of the Item. If I use mainPage.Fields["Address"].DisplayName, I get "Address".
How can I get the Display Name of the item from the droplink?
Use LookupField for getting reference item below are the sample code:
LookupField address= (LookupField)mainPage.Fields["Address"];
Item addressItem = address.TargetItem;
string displayName = addressItem.Fields["DisplayName"].Value;
If you want it in one line then use below code:
((LookupField)mainPage.Fields["Address"]).TargetItem.DisplayName
Type cast the field to a ReferenceField. Then access the TargetItem property:
sl += "<span class=\"address\">" + ((ReferenceField)mainPage.Fields["Address"]).TargetItem.DisplayName +"</span>";
The thomas answer would work based on your code. But I would suggest you also to try to stick with ASP.Net and Sitecore server components.
That will avoid Null Reference errors, will support Page Editor better and also makes your code easier to maintain.
You can have a repeater in your markup like this:
<asp:Repeater ID="rptAdresses" runat="server">
<ItemTemplate>
<span class="address">
<sc:Text id="scAddress" runat="server" Field="__Display Name" Item="<%#(Sitecore.Data.Items.Item)Container.DataItem%>"></sc:Text>
</span>
</ItemTemplate>
</asp:Repeater>
And then bind the address on your code behind:
private void BindRepeater()
{
if (mainPage.TemplateID.ToString() != "{27A9692F-AE94-4507-8714-5BBBE1DB88FC}")
{
rptAdresses.Visible = false;
}
else
{
rptAdresses.DataSource = Sitecore.Context.Item.GetChildren();
rptAdresses.DataBind();
}
}
Another point that I notice was the line mainPage.TemplateID.ToString() != "{27A9692F-AE94-4507-8714-5BBBE1DB88FC}". That is a point that you also could improve. Hard coded IDs are not a good pratice. You could create a class to hold those things or, even better, you could think more about your design to avoid it.
cheers
All other solutions are perfect, but you can also use the code below:
var itemID=mainPage.Fields["Address"].value;
Item targetItem=Sitecore.Context.Database.GetItem(itemID);
if (mainPage.TemplateID.ToString() == "{27A9692F-AE94-4507-8714-5BBBE1DB88FC}")
{
sl += "<span class=\"address\">" + targetItem.DisplayName +"</span>";
}
else
{
}
With this approach you can use every field of target item.

Storing records in a dropdownlist from DB without using LINQ Data source

I have a website for dance academy where Users can register and add/drop dance classes.
In the web page to drop a particular dance, for a particular user, the dropdown displays her registered dances.
Now I want to delete one of the dances from the list.
So i'll remove the row from the table and also from the dropdownlist. The problem is that every time the item with the lowest ID (index) is getting deleted, no matter which one the user selects.
I think I am storing the DataTextField and DataValueField for the dropdown incorrectly. Can someone please help me out?
The code is:
private void PopulateDanceDropDown()
{
var registereddanceList = from dd in context.DANCER_AND_DANCE
where dd.UserId == dancerId
select new
{
Text = dd.DanceName,
Value = dd.DanceId
};
dances.DataSource = registereddanceList;
dances.DataTextField = "Text";
dances.DataValueField = "Value";
dances.DataBind();
}
protected void dropthedance(object o, EventArgs e)
{
String strDataValueField = dances.SelectedItem.Value;
int danceIDFromDropDown = Convert.ToInt32(strDataValueField);
var dancer_dance = from dd in context.DANCER_AND_DANCE
where dd.DanceId == danceIDFromDropDown
select dd;
foreach (var dndd in dancer_dance)
{
context.DANCER_AND_DANCE.DeleteOnSubmit(dndd);
}
try
{
context.SubmitChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
PopulateDanceDropDown();
}
<asp:DropDownList ID = "dances" runat="server">
</asp:DropDownList>
<asp:Button ID="dropDance" runat="server" OnClick="dropthedance" Text="Drop Class" BackColor="Maroon" ForeColor="#FFCC99"/>
As your question says you want to access records without storing it in Linq.
So below one could be an alternative for you.
First store all the data from Database to, lets say List<NameIDPair>
Heres what NameIDPair could be:
class NameIDPair
{
public NameIDPair(){}
public string NameValue{get;set;}
public string IDValue{get;set;}
}
Then populate drop down list as follows:
List<NameIDPair> storeInMe = From Database
foreach(NameIDPair pair in storeInMe )
{
ListItem item = new ListItem();
item.Value = pair.IDValue;
item.Text = pair.NameValue;
ddldancesList.Items.Add(item);
}
Then for droppingTheDance, you can call the delete stored procedure to delete the same...
Hope this helps...

How To Create TextBox Control Dynamically at Runtime/ problems with .cs

This page is to retrieve data and display in the page and enable user to edit the info.
at this moment i need to retrieve the data and display it in textbox.
as i also have to retrieve multiple data from data and display on each different text box.
my .cs code is as follows:
foreach (DataRow dr in ChildImageDT.Rows)
{
myImage = new Images();
myImage.DateTaken = DateTime.Parse(dr["image_taken_dt"].ToString());
myImage.PlaceTaken = dr["image_taken_loc"].ToString();
myImage.DetailedInfo = dr["image_info"].ToString();
tableString += "<tr><td>Date Taken:</td>";
tableString += "<td><asp:TextBox ID=\"txtDateOfBirth\">" + myImage.DateTaken + "</asp:TextBox>";
tableString += "<asp:CalendarExtender ID=\"CalendarExtender1\" runat=\"server\" CssClass=\"AjaxCalendar\"";
tableString += "PopupButtonID=\"imgCalendar\" PopupPosition=\"Right\" TargetControlID=\"txtDateOfBirth\" Format=\"MM/dd/yyyy\"></asp:CalendarExtender>";
**tableString += "<asp:TextBoxWatermarkExtender ID=\"TextBoxWatermarkExtender1\" runat=\"server\" TargetControlID=\"txtDateOfBirth\" WatermarkText=\"Month/Day/Year\" WatermarkCssClass=\"watermarked\"></asp:TextBoxWatermarkExtender>";**
tableString += "<asp:Image ID=\"imgCalendar\" runat=\"server\" ImageUrl=\"img/Button/calendar.png\" Width=\"20px\" /></td>";
**tableString += "<td rowspan=3 ><input type=\"button\" class=\"right_content\" title=\"" + " " + "\"";
tableString += "onClick =\"location.href='ViewProfile.aspx?cid=" + "" + "'\" ";
tableString += "style=\"background-size:100%; background:url('/img/missing%20children%20pictures/";**
tableString += "" + ".jpg')\"/></td></tr>";
tableString += "<tr><td>Place Taken:</td>";
**tableString += "<td>" + textbox1.Text = myImage.PlaceTaken;**
tableString += "</td><td></td></tr>";
tableString += "<tr><td rowspan=3>Detailed Info:</td>";
tableString += "<td rowspan=3><input id=\"txtImageDetailedInfo\" type=\"text\">" + myImage.DetailedInfo + "</input></td><td></td></tr>";
tableString += "<tr><td><input id=\"SetProfilePicture\" type=\"radio\" /></td></tr>";
tableString += "<tr><td><input id=\"DeletePhoto\" type=\"checkbox\" /></td></tr>";
}
the page should look like this :
where each photo as it own description and i need to retrieve all the images and data from
What for you need this? I thing you have a bad design of you application and the best solution of your issue its to use another method do display your data and controls. As I understand you – you need to display many repeater blocks of data, wich include your textboxes. Try to read about Repeater Control. For example, your problem will have next solution:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<table>
<tr>
<td>UserName:</td>
<td><asp:TextBox ID="txtName" runat="server" /></td>
</tr>
<tr>
<td>Image:</td>
<td><asp:TextBox ID="txtPassword" Text="<%#Eval("Password")%>" runat="server" /></td>
</tr>
<tr>
<td>Image:</td>
<td><asp:Image ID="TextBox1" ImageUrl="<%#Eval("ImgUrl")%>" runat="server" /></td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
And in code you can use your repeater like that:
public partial class _Default : System.Web.UI.Page
{
private class User
{
public string Name { get; set; }
public string Password { get; set; }
public string ImageUrl { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
var userList = new[] {
new User {Name = "user1", Password = "pass1", ImageUrl = "img1.jpg"},
new User {Name = "user2", Password = "pass2", ImageUrl = "img2.jpg"},
new User {Name = "user3", Password = "pass3", ImageUrl = "img3.jpg"},
};
Repeater1.DataSource = userList;
Repeater1.DataBind();
}
}
Mor about Repeater you can read here
You should use Repeater control or some other data repeater control for building such layouts.
I think you can author your code in better way. I suggest two ways:
You can use PlaceHolder control and add control to place holder. You can add the html via Literal Control.
LiteralControl lit = new LiteralControl("<tr><td>Date Taken:</td>");
placeHolder1.Controls.Add(lit);
[Code]
var txt = new TextBox();
txt.Text = [Data];
PlaceHolder1.Controls.Add(txt);
you can override the Render page event and write html by HTMLTextWriter.
protected override void Render(HtmlTextWriter output) {
output.Write ("<h3> Hello </h3>");
}
According your question:
i have tried this but could u guide me on how to use foreach (DataRow dr in ChildImageDT.Rows) with repeater.. i cant seem to get to populate out the data
Try to do next:
var userList = new List<User>();
foreach (DataRow row in dataTable.Rows)
{
var user = new User()
{
Name = row["Name"].ToString(),
Password = row["Password"].ToString(),
ImageUrl = row["ImageUrl"].ToString()
};
userList.Add(user);
}
repeater1.DataSource = userList;
repeater1.DataBind();
}
Of course, you need to define your class, that implement data contrcats, accordin your task.
And i strongly recommend you, spend one or two days to read chapter about Repeater. Believe me, if you do it - your progress of your create yuor program is much accelerated.
p.s.: try to ready about Linq - its very powerfull technology to replace your foreach in task, like this.
You need to build up the control tree properly. For example you need to instantiate a TextBox (TextBox txt = new TextBox()) and add it to the Controls collection of another control. For this type of thing I would define an asp:Panel in markup and add my dynamic controls in the code behind

Categories