How to get the value of controls inside aspx page with reflection - asp.net

Hello i'm using this to get the value of a control but control collection is null:
Type type = BuildManager.GetCompiledType("~/Default.aspx");
Page pageView = (Page)Activator.CreateInstance(type);
Label lbl1 = (Label) pageView.FindControl("lbl1");
string lbl1Value = lbl1.Text;
If add a quick watch in Visual Studio i can see that PageView.Context has the value of the label, but PageView.Context is protected, so i don't know how to access it at runtime

I've solved the problem, the page doesn't show controls value during reflection because i've setted the property autoevent wireup=false

Related

WebUserControl changes to Viewstate are not accessible at page level

I'm developing an ASP.NET Webforms application and while using the WebUserControl I stumbled upon a behavior I dont understand.
My WebUserControl puts 4 strings into the ViewState:
var projectCode = SelectedProject.Value;
ViewState["ProjectCode"] = projectCode;
var resourceId = SelectedResource.Value;
ViewState["ResourceCode"] = resourceId;
var indicatorId = SelectedIndicator.Value;
ViewState["IndicatorCode"] = indicatorId;
var areaCode = SelectedArea.Value;
ViewState["AreaCode"] = areaCode;
When thats done, my page should get these values from the ViewState, but the ViewState does not contain any items and returns null for all 4 keys.
Why is the ViewState on the page level empty? And if I shouldn't use the ViewState for this, whats the best method to pass values forth and back?
Because the keys you are using are local for the current usercontrol: the "AreaCode" defined in the viewstate for the UserControl is not the same as the one defined for the page.
This behaviour is different from the Session one.
You can use the Session dictionary or implement some public methods on your user control to retrieve the values.

Setting values when a user updates a record using Entity Framework 4 and VB.NET in ASP.NET application

this is my first post, hopefully I'm following the rules!
After a few weeks of banging my head against brick walls and endless hours of internet searches, I have decided I need to make my own post and hopefully find the answers and guidance from all you experts.
I am building an ASP.NET application (in Visual Studio 2010) which uses an SQL 2008 database and Entity Framework 4 to join the two parts together. I designed the database as a database project first, then built the Entity Model as a class project which is then referenced in the main ASP.NET project. I believe this is called Database First in Entity Framwork terms?
I'm fairly new to Web Apps (I mainly develop WinForms apps) and this is my first attempt at using Entity Framwork.
I can just about understand C# so any code samples or snippets you might supply would be preferred in VB if possible.
To give some background on where I am so far. I built a regsitration page called register.aspx and created a wizard style form using ASP:Wizard with ASP:TextBox, ASP:DropdownList and ASP:CheckBoxList it's all laid out inside a HTML table and uses CSS for some of the formatting. Once the user gets the the last page in the wizard and presses "Finish" I execute some code in the VB code behind file as follows:
Protected Sub wizardRegister_FinishButtonClick(sender As Object, e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wizardRegister.FinishButtonClick
Dim context As New CPMModel.CPMEntities
Dim person As New CPMModel.Person
Dim employee As New CPMModel.Employee
Dim newID As Guid = Guid.NewGuid
With person
.ID = newID
.UserID = txbx_UserName.Text
.Title = ddl_Title.SelectedValue
.FirstName = txbx_FirstName.Text
.MiddleInitial = txbx_MiddleInitial.Text
.FamilyName = txbx_FamilyName.Text
.Gender = ddl_Gender.SelectedValue
.DOB = txbx_DOB.Text
.RegistrationDate = Date.Now
.RegistrationMethod = "W"
.ContactMethodID = New Guid(ddl_ContactMethodList.SelectedValue)
.UserName = txbx_UserName.Text
If Not (My.Settings.AuthenticationUsingAD) Then
.Password = txbx_Password.Text ' [todo] write call to salted password hash function
End If
.IsRedundant = False
.IsLocked = False
End With
context.AddToPeople(person)
With employee
.ID = newID
.PayrollNumber = txbx_PayrollNumber.Text
.JobTitle = txbx_JobTitle.Text
.DepartmentID = ddl_DepartmentList.SelectedValue
.OfficeNumber = txbx_OfficeNumber.Text
.HomeNumber = txbx_HomeNumber.Text
.MobileNumber = txbx_MobileNumber.Text
.BleepNumber = txbx_BleepNumber.Text
.OfficeEmail = txbx_OfficeEmail.Text
.HomeEmail = txbx_HomeEmail.Text
.IsRedundant = False
.RedundantDate = Nothing
'--------------------------
.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
.FiledLocation = My.Computer.Name
.FiledDateTimeStamp = Date.Now
'----------------------------
End With
context.AddToEmployees(employee)
context.SaveChanges()
End Sub
The above works fine, seemed to be a sensible way of doing it (remember I'm new to Entity Framework) and gave me the results I extpected.
I have another page called manage.aspx on this page is a tab control, each tab page contains a asp:DetailsView which is bound to an asp:EntityDataSource, I have enabled Update on all the Entity Data Sources and on some I have also enabled Insert, none of the have delete enabled.
If I build and run the app at this stage everything works fine, you can press the "edit" link make changes and then press "update" and sure enough those updates are displayed on the screen instantly and the database does have the correct values in.
Here's the problem, I need to intercept the update in the above code (the bold bit) notice there is a column in my database called FiledBy, FiledLocation, and FiledDateTimeStamp. I don't want to show these columns to the user viewing the ASP.NET page but I want to update them when the user presses update (if there were any changes made). I have tried converting the ASP:DetailsView into a template and then coding the HTML side with things like;
<## Eval(User.Name) #>
I did manage to get it to put the correct values in the textboxes when in edit mode but I had the following problems;
It didn't save to the database
I have to show the textboxes which I don't want to do
I have read on several other posts on here and other websites that you can override the SaveChanges part of the Entity Framwork model one example of this is in the code below;
public override int SaveChanges()
{
var entities = ChangeTracker.Entries<YourEntityType>()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity);
var currentDate = DateTime.Now;
foreach(var entity in entities)
{
entity.Date = currentDate;
}
return base.SaveChanges();
}
The problem is, that whilst I understand the idea, and can just about transalate it to VB I have no idea how to implement this. Where do I put the code? How do I call the code? etc.
I would ideally like to find a solution that meets the following requirements:
Doesn't get overwritten if I was to regenerate / update the Entity Model
Doesn't need to be copy and pasted for every table in my model (most but not all have the audit columns in)
Can be used for other columns, for example, if a user make a selection in a check list I may want to write some value into another (not exposed to the user) column.
Am I taking the right approach to displaying data in may webpages I certainly find the DataView and GridView limiting, I did think about creating a form like the registration form in table tags but have no Idea how to populate the textboxes etc with values from the database nor how to implement paging as many of the tables have one to many relationships, although saving changes would be easy if I did populate textboxes on a table.
Thank you all in advance to anyone who offers there support.
Kevin.
Ok so I have now got closer, but still not got it working correctly. I've used the following code to edit the value in the DetailsView on the Databound event. If writes the correct timestamp into the read only textbox but does not right this value back to the database when you press the Update button on the DetailsView control.
Protected Sub dv_Employee_DataBound(sender As Object, e As EventArgs) Handles dv_Employee.DataBound
If dv_Employee.CurrentMode = DetailsViewMode.Edit Then
For Each row In dv_Employee.Rows
If row.Cells(0).Text = "FiledDateTimeStamp" Then
row.Cells(1).Text = Date.Now()
End If
Next
End If
End Sub
I like the idea of overriding the save changes method. Your context should be a partial class, so you just need to define another class marked as partial with the same name in the same namespace and add the override to it.
Namespace CPMModel
Partial Public Class CPMEntities
...Your override here
End Class
Since this is an override of the default SaveChanges method you do not need to make any changes in how it is called. You will need to find a way to gain access to entity level properties.
Since this is the method that commits changes for all entities you will not be able to access the properties like you do in your example, since the entity class does not define an of your concrete properties. So you need to create partial classes for your entities and have them all implement an interface that defines the properties you would like to interact with.
Create interface:
Interface IDate
Property Date() as DateTime
End Interface
Create partial class for each of your entities that implements the IDate interface. (The same rules apply for these partial classes they must be marked partial, have the same name as the class they extend and live in the same namespace) Then in your SaveChanges override
public override int SaveChanges()
{
var entities = ChangeTracker.Entries<Entity>()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity);
var currentDate = DateTime.Now;
foreach(var entity in entities)
{
***Now cast entity to type of IDate and set your value ***
entity.Date = currentDate;
}
return base.SaveChanges();
}
I don't write in Vb so I left the syntax in C#.
That should fulfill all of your requirements.
Ok, so this isn't exactly how I imagined it would work but it has infact met my needs. Kind of!
What I did was Write a Protected Sub in the code behind file of the aspx file.
Protected Sub CustomEntityUpdate_Employee(sender As Object, e As
EntityDataSourceChangingEventArgs)
Dim emp As CPMModel.Employee = e.Entity
' Check if the entity state is modified and update auditing columns
If emp.EntityState = EntityState.Modified Then
emp.FiledDateTimeStamp = Date.Now()
emp.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
emp.FiledLocation = My.Computer.Name
End If
End Sub
Then in the aspx page I edited the Entity datasource code to call the above sub routine
#nUpdating="CustomEntityUpdate_Employee"
<asp:EntityDataSource
ID="eds_Employee"
runat="server"
ConnectionString="name=CPMEntities"
DefaultContainerName="CPMEntities"
EnableFlattening="False"
EnableUpdate="True"
EntitySetName="Employees"
AutoGenerateWhereClause="True"
Where=""
EntityTypeFilter="Employee"
**OnUpdating="CustomEntityUpdate_Employee">**
<WhereParameters>
<asp:SessionParameter
Name="ID"
SessionField="UserID" />
</WhereParameters>
</asp:EntityDataSource>
The Protected Sub, checks if the entity has been modified and if it has updates the entity auditing columns with the values I wanted.
It works but it will certainly make for a lot more code, I ideally would like a way to package this up perhaps into a class and just call the sub from the various aspx pages via the OnUpdating event and have the class figure out which entity was making the call and handle all the logic there.

Request.Form "Collection is only readonly" when trying to set text box content

Saving the values in the Lists & works fine.
abc= (ABC)(Session["xml"]);
string ctrlStr = String.Empty;
foreach (string ctl in Page.Request.Form)
{
if (ctl.Contains("something"))
{
ctrlStr = ctl.ToString();
abc.student[0].marks[j].science.something.Value = Convert.ToDecimal(Request.Form[ctrlStr]);
}
Want to retrieve the values from the saved object when I click on edit button back on the respective dynamic textboxes....
foreach (string ctl in Page.Request.Form)
{
if (ctl.Contains("studentname"))
{
ctrlStr = ctl.ToString();
(Request.Form[ctrlStr]) = abc.student[0].marks[x].science.studentname.ToString();---Gives an error stating the collection is only readonly
}
}
Request.Form — like the Request object generally — is read-only, reflecting the fact that, by the time you are responding to a request, the request itself cannot be changed. ASP.NET uses the values from the form POST to create server controls on the Page, and these allow you to control the values of the input and other form elements that are written to the Response object.
In your case, the TextBox controls are being generated dynamically, so they are not automatically bound to form values — hence your problem. You will need to keep references to the controls when they are created (or find them afterwards using the FindControl() method) and set their Text property.
(original answer follows)
The Controls collection becomes read-only at a certain point in the construction of the page. You have to do manipulation before that point. I don't remember offhand when it is, but you're safe with OnLoad through OnPreRender.
Where is your code firing from?
Update: Okay, I see what you're trying to do. This will be easiest if you're dealing with server-side controls (that is, controls generated by ASP.NET. That would look like this in your aspx (or ascx):
<asp:TextBox runat="server" ID="studentname"/>
Then you could update the value like this:
abc = (ABC)(Session["xml"]);
studentname.Text = abc.student[0].marks[j].science.something.Value.ToString();
That will set the value of the studentname text box automatically without needing to search through all of the Request.Form items. (Assuming you set j somewhere... I don't know the context for that.)
I can't tell for sure from your code, but it looks like you may just have a "plan HTML" input, which would look more like this:
<input type="text" name="studentname"/>
In that case, there is no simple way to update the value from your page's code, so I'd start by making sure that you're using server-side controls.
You can set the Request.Form values with reflection:
Request.Form.GetType().BaseType.BaseType.GetField("_readOnly", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(Request.Form, false);
Request.Form["foo"] = "bar";
What you are trying to achieve?
The Form collection retrieves the values of form elements posted to the HTTP request body, with a form using the POST method. - http://msdn.microsoft.com/en-us/library/ms525985(v=vs.90).aspx

Binding LinqDataSource from code-behind to Gridview

i have a grdidview control on the .aspx page and i am trying to connect dynamically from code behind and bind the gridview but somehow it throwing me an error... what is wrong with this code? any help?
LinqDataSource LDS_POReport = new LinqDataSource();
LDS_POReport.ContextTypeName = "DataContextDataContext";
LDS_POReport.Selecting += new EventHandler<LinqDataSourceSelectEventArgs>(LinqDataSourcePO_Selecting);
this.gvReport.DataSource = "LDS_POReport";
//this.gvReport.DataBind();
Update:
after i update the code to
this.gvReport.DataSource = LDS_POReport;
it works fine but when i try to sort i get this error:
The GridView 'gvReport' fired event Sorting
which wasn't handled.
i added this but no effect.
LDS_POReport.AutoPage = true;
LDS_POReport.AutoSort = true;
I guess that your problem is here:
this.gvReport.DataSource = "LDS_POReport";
The above code line attempts to assign a string to a property that expects some sort of data source. I assume that you really intended to assign the LinqDataSource object itself:
this.gvReport.DataSource = LDS_POReport;
First thing, the DataSource should get a reference to the object containing the data, not the name of the object containing the data. GridViews can work reflectively, but not THAT reflectively.

How do you assign a specific NAME to a tag when using master pages?

I am using Master Pages and I am truing to dynamically add hidden text boxes on the form with the NAMEs that Google Checkout expects.
<input name="item_name_1" type="hidden" value="Widget #1"/>
Using VB.NET, I execute the following code
'Name
Dim hidName As New HtmlInputHidden
hidName.ID = "item_name_" & count.ToString
hidName.Value = item
Form.Controls.Add(hidName)
But because I use Master Pages, the control is renamed to "ctl00$item_name_1".
<input name="ctl00$item_name_1" type="hidden" id="ctl00_item_name_1"
Note that I tried to set the Name property (hidName.Name = "item_name_" & count.ToString) and also tried to add the name to the Attributes list. This strangely had no effect on the name attribute whatsoever. When I am not using master pages, I notice that when I set the ID property the NAME is automatically assigned the same value.
Is there a way to control the name of a dynamically added control when you are using master pages?
System.Web.UI.WebControls.Control has a property called ClientIDMode.
Instead of HtmlInputHidden, you may use a HiddenField.
'Name
Dim hidName As New System.Web.UI.WebControls.HiddenField
hidName.ID = "item_name_" & count.ToString
hidName.ClientIDMode = System.Web.UI.ClientIDMode.Static
hidName.Value = item
Form.Controls.Add(hidName)
See Making text box hidden in ASP.NET and HiddenField Class.
The ClientIDMode was introduced in the .Net Framework 4.0.
For earlier versions, an alternative could be adding a asp:Literal.
'Name
Dim hidName As New System.Web.UI.WebControls.Literal
hidName.Text = _
String.Format("<input name=""item_name_{0}"" type=""hidden"" value=""{1}""/>", _
count, item)
Form.Controls.Add(hidName)
Unfortunately, the simple answer is No. The more difficult answer is Yes, but not in a straightforward way. A workaround is not to try to set the property but instead define the name as an attribute:
Dim hidName As New HtmlInputHidden
hidName.Attributes("Name") = "item_name_" & count.ToString
hidName.Value = item
Form.Controls.Add(hidName)

Resources