Validation when converting .aspx to .ascx - c#

I'm currently converting a set of .aspx pages and the VB code behind them to .ascx and C#.
I'm most of the way through the project now but have become a bit stuck as I'm fairly new to ASP.net.
Basically the system I'm working with validates a shopping basket but with me changing the class the code inherits from I'm having issues working out what I should change it too.
I'm changing from System.Web.UI.Page to System.Web.UI.UserControl and am primarily having problems with the Validator.Add(v) element of the code below:
public override void Validate()
{
base.Validate();
if (Profile.ShoppingCart == null || Profile.ShoppingCart.Items.Count == 0)
{
CustomValidator v = new CustomValidator();
v.ErrorMessage = "You must have at least 1 course in your basket.";
v.IsValid = false;
Validator.Add(v);
}
}
So if anyone could provide assitance it would be appreciated.

Each user control contains a reference to the page that it is contained in.
Page.Validators.Add(v);

Related

ASP.NET Web Page Globalization & Localization in Master Page C# 3.0

I cant use the following code in Master page for Globalization & Localization. It gives the error as commented in the code part "does not contain a defination for InitializeCulture"
protected override void InitializeCulture()
{
if (Request["Language"] != null)
{
//String selectedLanguage = Request["Language"];
// code wil go here
}
base.InitializeCulture();
//base.InitializeCulture gives error as mentioned in the next line
//does not contain a defination for InitializeCulture
}
When i add this code to other pages other than Master Page it works fine. is there any restriction on using this code in Master Page.
If i am able to define this code in Master Page then i dont need to write this code in every file.
Am i doing something wrong, I have include File for threading and Globalization, Still it doesn't work in Master Page
You have to do this (= override InitializeCulture) in your Page class. It doesn't work in the master page (MasterPage is derived from Control, not from page). I would suggest that you implement a base class which is derived from Page and derive every web form from this class, then you also have to write the code only once. It is always handy to have your own base class.
In Visual Studio you add a new class PageBase.cs:
public class FormBase : Page
{
protected override InitializeCulture()
{
if (Request.Form["lbCulture"] != null)
{
String selectedLanguage = Request.Form["lbCulture"];
UICulture = selectedLanguage;
Culture = selectedLanguage;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(selectedLanguage);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(selectedLanguage);
}
base.InitializeCulture();
}
}
The current culture is either stored in some dropdown listbox, in the session or passed by query string. I used a listbox in the sample.
And then you derive your WebForm from this page like this:
public class Default : FormBase // instead of deriving from Page

Master Page is adding additional text in TextBox ID

I have a master page which has a content section with the id cpMainContent.
I am using this master page on every webform I am creating for college project. One of such form is frmSearchPersonnel. The purpose of frmSearchPersonnel is to ask user last name of the person they want to search in a textbox and then click on search button. The ID of TextBox is
txtSearchName
Search button will do postbackUrl transfer to another form which I have named frmViewPersonnel.
In frmViewPersonnel I am trying to use following code.
NameValueCollection myRequest = Request.Form;
if(!string.IsEmptyOrNull(myRequest["txtSearchName"]))
string strSearch = myRequest["txtSearchName"];
The problem I ran into is that this didn't find any control with the name of txtSearchName. While debugging I found this in myRequest object,
[5] "ctl00$cpMainContent$txtSearchName" string
Even though when I added textbox I gave it ID of txtSearchName but when page is rendered it is adding extra string from master page.
How can I stop this? I have to use master page so don't say not to use master page :)
Why is it doing that?
Update
While Googling and Binging I found that I can use Control.ClientID in this case so looking into it.
Update 2
As suggested below to add ClientIDMode="static" in the html of control or add it in page directive. What it does is, it keeps the ID static to txtSearchName but problem is this,
<input name="ctl00$cpMainContent$txtSearchName" type="text" id="txtSearchName" />
Here name is still using ctl00 and the code I showed above,
string strSearch = myRequest["txtSearchName"]
it still won't work because nvc collection is either searchable by index or name not the id directly.
==============
You need to add a ClientIDMode="Static" to the html of the textbox:
<asp:TextBox ID="txtSearchName" runat="server" ClientIDMode="Static" />
It happens to prevent duplicate ID's. Usually it happens when you use master pages as it contains nested pages
If you want all controls with ClientIDMode="Static", you can put it in the page header of the master file.
<%# Page Language="C#" ClientIDMode="Static" %>
If you are posting to another page that uses the same master page (called SiteMaster in my case), the name of the textbox should be same the same.
string val = Request[((SiteMaster)Master).txtSearchName.UniqueID];
If you're NOT posting to a page with the same master, well, then are you using the viewstate for the textbox at all since you're posting to another page? If not, just make the control a non asp.net control:
<input type="text" name="txtSearchName"/>
If you are using viewstate and posting to another page with a different master page, well, you should use PreviousPage.
Little late here. Appreciate #aquinas and #rudeovski ze bear. Interesting and good answers.
I'd same issue and I solved it differently.
In fact, I used a public Interface.
public interface ISearch
{
string SearchText { get; }
}
Then implement ISearch interface in two aspx page say One.aspx and Two.aspx classes.
--One.aspx-- (Where I'v added TextBox1, and Button1 and set Button1.PostBackUrl="~/Two.aspx")
public partial class One : System.Web.UI.Page , ISearch
{
public string SearchText
{
get
{
return TextBox1.Text;
}
}
}
--Two.aspx--
public partial class Two : System.Web.UI.Page, ISearch
{
protected void Page_Load(object sender, EventArgs e)
{
ISearch search = (ISearch) PreviousPage;
Label1.Text = search.SearchText;
}
public string SearchText
{
get
{
throw new NotImplementedException();
}
}
}
If your try to access the input element value in code behind on post back instead of for example:
var emailAddress = Request.Form["ctl00$ctl00$ctl00$ContentContainer$MainContent$MainContent$ContentBottom$ProfileFormView$emailaddress1"];
Use
var emailAddressKeyName = Request.Form.AllKeys.FirstOrDefault(a => a.Contains("emailaddress1"));
var emailAddress = Request.Form[emailAddressKeyName];

C# syntax to get access to webcontrol in different file (aspx)

Within my Website project, I have some aspx pages, javascript files, and a custom C# class I called MyCustomReport. I placed a Image box with an ID of Image1 inside SelectionReport.aspx. I need to get access to that Image1 inside MyCustomReport.cs so I can turn it on and off based on conditions. What code do I need to do this? Thanks everyone
You'll need to pass the instance of Image control to MyCustomReport. From there you'll be able to set it's Visible property to true or false.
Probably something like this
public partial class SelectionReport : Page
{
// your code here
protected void Page_Load( object sender, EventArgs e ){
MyCustomReport myCustomReport = new MyCustomReport();
myCustomReport.MyReport( Image1 );
}
}
public class MyCustomReport
{
public void MyReport( Image arg ){
// some more code
arg.Visible = false; // or true
}
}
EDIT derek is right, you won't need the entire page, just the image.
it sounds a bit odd to do it that way. You could pass the control to the class method using the ref keyword, then the class could modify it:
doSomething(data, MyUserControl);
I think a better implementation would be for your class to have a method or property that the page could query to turn the control on or off.

Persisting User Input for Dynamic Control in SharePoint Web Part

Edit at bottom with solution
I've seen a similar question to this posted before and have tried the suggestions, but I must be missing something. My basic problem is this: I have a select box where the user can select a filter which may or may not have constraints built into it (requires the user to input further data so the filter knows how to filter). Since it's unknown just how many constraints will exist for the filter, I'm trying to load them in dynamically and add them to a placeholder panel that I have. The correct number of constraints load just fine and dandy, but when the user inputs text and hits submit, after the page reloads none of the values persist. Here's the appropriate code (I can provide more if needed):
I have these as class variables for my Web Part:
Panel constraintPanel;
HtmlInputText[] constraints;
Label[] constraintLabels = null;
Inside an override CreateChildControls I initialize the panel:
constraintPanel = new Panel();
I build in the dynamic input boxes in an overridden OnPreRender (Note: I've heard people say to do it in OnInit, OnLoad, or OnPreRender, but OnPreRender is the only one that doesn't make the whole Web Part error out):
protected override void OnPreRender(EventArgs e)
{
buildConstraints();
base.OnPreRender(e);
}
private void buildConstraints()
{
if (!viewSelect.SelectedValue.Equals(INConstants.NoFilterOption))
{
string[,] constraintList = docManager.GetFilterConstraints(viewFilterSelect.SelectedValue);
if (constraintList != null)
{
this.constraints = new HtmlInputText[constraintList.Length / 2];
this.constraintLabels = new Label[constraintList.Length / 2];
for (int constraintCount = 0; constraintCount < constraintList.Length / 2; constraintCount++)
{
Label constraintLabel = new Label();
constraintPanel.Controls.Add(constraintLabel);
constraintLabel.Text = constraintList[constraintCount, 0];
this.constraintLabels[constraintCount] = constraintLabel;
HtmlInputText constraint = new HtmlInputText();
constraintPanel.Controls.Add(constraint);
constraint.ID = "constraint_" + constraintCount;
constraint.MaxLength = 12;
constraint.Style.Add("FONT-FAMILY", "Verdana");
constraint.Style.Add("FONT-SIZE", "11");
this.constraints[constraintCount] = constraint;
}
}
}
}
And then finally inside an overridden RenderWebParts I have (note: I've also tried looping through the arrays constraints and constraintLabels to render the controls, but it made no difference):
...
constraintPanel.RenderBeginTag(output); // not sure if this is needed
if (constraints != null && constraints.Length > 0)
{
foreach (Control tempControl in constraintPanel.Controls)
{
if (tempControl is Label)
{
output.WriteLine("<tr>");
output.WriteLine("<td width='2%' nowrap><font class='search-header'>");
tempControl.RenderControl(output);
output.WriteLine(" ");
}
else if (tempControl is HtmlInputText)
{
tempControl.RenderControl(output);
output.WriteLine("</td>");
output.WriteLine("<td width='*' nowrap></td>");
output.WriteLine("</tr>");
}
}
}
constraintPanel.RenderEndTag(output); // not sure if this is needed
...
I appreciate any help, as this is truly driving me crazy.
Edit with solution:
I've been able to get it working. I needed to override the OnLoad event and wrap my calls from there in a try-catch block. For some reason the initial page load throws an exception when trying to run, which causes the entire page to not display. I also forgot to add my constraintPanel to the Controls list.
Here's the code in OnLoad for information's sake:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
try
{
viewsBuildConstraints();
}
catch (Exception)
{
}
}
Try marking your webpart with the INamingContainer interface and make sure to give all controls an ID. Furthermore, HtmlInput COntrols do not have a viewstate i believe, which would cause them to "forget" the input after a postback. Could you try using actual TextBox controls?

Convert C# to clientside Javascript

I have an Asp.Net page with a list of options accompanied by a checkbox in a ListView control. I have applied Paging using the paging control. However I want to maintain the status of the checkboxes across the various paged pages of the ListView. I have done this with the following code
private List<int> IDs
{
get
{
if (this.ViewState["IDs"] == null)
{
this.ViewState["IDs"] = new List<int>();
}
return (List<int>)this.ViewState["IDs"];
}
}
protected void AddRowstoIDList()
{
int checkAction = 0;
foreach (ListViewDataItem lvi in lvCharOrgs.Items)
{
CheckBox chkSelect = (CheckBox)lvi.FindControl("chkSelect");
if ((((chkSelect) != null)))
{
int ID = Convert.ToInt32(lvCharOrgs.DataKeys[lvi.DisplayIndex].Value);
if ((chkSelect.Checked && !this.IDs.Contains(ID)))
{
this.IDs.Add(ID);
checkAction += 1;
}
else if ((!chkSelect.Checked && this.IDs.Contains(ID)))
{
this.IDs.Remove(ID);
}
}
}
}
protected void lvCharOrgs_ItemDataBound(object sender, ListViewItemEventArgs e)
{
ListViewDataItem lvi = (ListViewDataItem)e.Item;
if ((lvi.ItemType == ListViewItemType.DataItem))
{
// Find the checkbox in the current row
CheckBox chkSelect = (CheckBox)lvi.FindControl("chkSelect");
// Make sure we're referencing the correct control
if ((chkSelect) != null)
{
// If the ID exists in our list then check the checkbox
int ID = Convert.ToInt32(lvCharOrgs.DataKeys[lvi.DisplayIndex].Value);
chkSelect.Checked = this.IDs.Contains(ID);
}
}
if (Profile.proUserType == "basic")
{//basic account so no choice of charity
((CheckBox)e.Item.FindControl("chkSelect")).Checked = true;
((CheckBox)e.Item.FindControl("chkSelect")).Enabled = false;
}
}
Now I have a CustomValidator control which checks to ensure between 3 & 5 records have been selected. If this is true the page is valid and processed. If it is not the case (eg less than 3 or more than 5) the page is Invalid and the CustomValidator throws up a label to notify of this fact.
I use the following code on the serverside to implement this.
protected void lvCharOrgsValidator_ServerValidate(object source, ServerValidateEventArgs args)
{// Custom validate lvCharOrgs
//update selected rows
AddRowstoIDList();
//get count and verify is correct range
int counter = this.IDs.Count;
args.IsValid = (counter >=3 && counter <=5) ? true : false;
}
This all works fine except I need to implement a 'ValidatorCallout' extender from the AJAX Control Toolkit. However this doesn't work with CustomValidators unless they implement clientSide validation. Thus I need to convert the 'lvCharOrgsValidator_ServerValidate' method to a clientside JavaScript function.
Hope this clarifies my requirements.
What does the following do?
AddRowstoIDList();
Something like the following is a start, but will need more details on the above method to provide a working answer
function validateRowCount(sender, args) {
//update selected rows
AddRowstoIDList(); // Does this add row indexes to an array?
//get count and verify is correct range
var counter = IDList.length;
args.IsValid = (counter >=3 && counter <=5);
}
It might be worth looking at Script# for a longer term solution, if you're planning on doing a lot of conversion.
EDIT:
now I can see the AddRowstoIDList() method, to do this on the client-side will be slightly different. Firstly, get a reference to the DOM element that is rendered for lvCharOrgs. Probably the most straightforward way to do this in vanilla JavaScript would be to put the JavaScript function in the page and use the server tags to get the rendered ClientID.
function validateRowCount(sender, args) {
var lvCharOrgs = document.getElementById('<%= lvCharOrgs.ClientID %>');
var checkboxes = lvCharOrgs.getElementsByTagName('input');
var len = checkboxes.length;
var counter = 0;
for(var i =0; i < len; i++) {
if (checkboxes[i].type == "checkbox" && checkboxes[i].checked) counter++;
}
args.IsValid = (counter >=3 && counter <=5);
}
Should work something like this - Working Demo
add /edit to the URL if you want to see the code
If you change int to var, your code is valid JavaScript. (But since it depends on other functions and objects you need to convert those as well.) Also if you're using the c# 3.5 compiler it will stay valid C# even with var instead of int.
Probably not what you want, but there is jsc:
"Web 2.0 hype? Want build better web
sites, but javascript is too hard? No
real IDE? Maybe you should try jsc.
The web app can be built within Visual
Studio 2008 or any other c# compliant
IDE, and then the application
magically appears. You should think of
it as a smart client. Precompile your
c# to javascript with jsc! As an
option instead of using IIS and
asp.net, you could get away by using
apache, with mysql and php."
Have a look at this article. It applies to asp.net mvc, but it also covers some basics and you might be able to do something similar for asp.net. In particular, you might find the jquery remote validation attributes shown in the article useful for what you intend to do.
SharpKit converts C# to client side javascript.
https://sharpkit.github.io/
Well, you can always include your own javascript with custom validators. Here is a link to an article that introduces adding javascript to a validator. You just have to write your own javascript, really.
I heard about a cross-compiler from c# (or was it IL?) to JavaScript but unfortunatly do not remember the name anymore, but a google-search turned up stuff like this: http://jsc.sourceforge.net/

Categories