Newbie here, I need help with a website I'm creating.
I have a class that does some analysis on some text that is input by the user, the class then finds an appropriate answer and sends it back to the textbox. (in theory)
Problem is I don't know how I can control and access the textbox on the default.aspx page from a class, all I get is "object reference is required non static field".
I made the textbox public in the designer file yet still no joy. :(
I've also read this: How can I access the controls on my ASP.NET page from a class within the solution? , which I think is along the lines of what I'm trying to achieve but I need clarification/step by step on how to achieve this.
Hope someone can point me in the right direction.
Many thanks,
Kal
This is the code I have added to the designer.cs file:
public global::System.Web.UI.WebControls.TextBox TextBox3;
public string MyTextBoxText
{
get
{
return TextBox3.Text;
}
set
{
TextBox3.Text = value;
}
}
This is the class method i have created:
public static cleanseMe(string input)
{
string utterance = input;
string cleansedUtt = Regex.Replace(utterance, #"[!]|[.]|[?]|[,]|[']", "");
WebApplication1._Default.TextBox3.text = cleansedUtt;
}
I could just return the cleansedUtt string i know, but is it possible for me to just append this string to the said textbox from this method, within this class?
I also tried it this way, i wrote a class that takes in the name of the textbox and string to append to that textbox. it works BUT only on the default.aspx page and does not recognise the textbox names within the difference classes. The code is as follows:
public class formControl
{
public static void ModifyText(TextBox textBox, string appendthis)
{
textBox.Text += appendthis + "\r\n";
}
I would suggest you that do not access the Page Controls like TextBox in your class. It will be more useful and a good practice that whatever functionality your class does, convert them into function which accept the parameters and returns some value and then on the basis of that value you can set the controls value.
So now you have reusable function that you can use from any of the page you want. You do not need to write it for every textbox.
Here I am giving you a simple example
public class Test
{
public bool IsValid(string value)
{
// Your logic
return true;
}
}
Now you can use it simple on your page like this
Test objTest = new Test();
bool result=objTest.IsValid(TextBox1.Text);
if(result)
{
TextBox1.Text="Everything is correct";
}
else
{
TextBox1.Text="Something went wrong";
}
If you have your class in the same project (Web Project) the following will work:
public class Test
{
public Test()
{
//
// TODO: Add constructor logic here
//
}
public static void ValidateTextBox(System.Web.UI.WebControls.TextBox txt)
{
//validation logic here
if (txt != null)
txt.Text = "Modified from class";
}
}
You can use this from your webform like this:
protected void Page_Load(object sender, EventArgs e)
{
Test.ValidateTextBox(this.txt);
}
If your class is in a different (class project), you would need to add a reference to System.Web to your project.
Related
I am trying to pass a few parameters between two web pages
within the source page I have the following properties
private string _testString { get; set; }
public string TestString
{
get
{
return _testString;
}
}
In previous msdn examples the return type was always set to a UI element (textbox.text)
However I am trying to pass the value from a dynamically generated link button which is why I chose to use the private accessor
In the click event of the link button on the source page I have the following:
protected void RenderReportInNewPage(LinkButton lb)
{
_testString = lb.CommandArgument.ToString();
Response.BufferOutput = true;
Response.Redirect("~/stuff/testviewer.aspx");
}
On the target page I have the source page referenced in the aspx as follows:
<%# PreviousPageType VirtualPath="~/stuff/testviewer.aspx"%>
And then in the codebehind of the target page I have the following:
Textbox.Text = PreviousPage.TestString;
PreviousPage displays the public property TestString but it is always null (as I don't think it is getting set but not sure why)
Is is possible to set a private accessor (_teststring) and have that value reflected within the public property? I'd appreciate any suggestions on what I have done wrong.
-Cheers
Found the error. It was not in the setting of the property but in how I was invoking the target page. In order to pass the properties across I needed to user Server.Transfer instead of Response.Redirect
protected void RenderReportInNewPage(LinkButton lb)
{
_testString = lb.CommandArgument.ToString();
Response.BufferOutput = true;
Server.Transfer("~/ReportBuilder/viewer.aspx");
}
-cheers
I searched the web but haven't found a real good answer for this question..
Let's say I have a form, on AddToList.aspx, and i want that after you hit send, it will direct you back to List.aspx, with a message "The Item was added to list" in a message box div.
do i need to send List.aspx?msg=my message, or is there another good way of doing it?
EDIT:
so i made this helper class:
public class MessageHelper : System.Web.UI.MasterPage
{
public void SetMessage(String message)
{
Session["Message"] = message;
}
public string GetMessage()
{
if (String.IsNullOrEmpty(Session["Message"]))
{
String temp = Session["Message"];
Session["Message"] = "";
return temp;
}
else
{
return "";
}
}
}
and got this error:
Error 32 The best overloaded method match for 'string.IsNullOrEmpty(string)' has some invalid arguments
Error 33 Argument '1': cannot convert from 'object' to 'string'
Error 34 Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?)
You need to convert to string. Session parameters are stored as objects.
It may also be userful to implement this as a extension method. This way it will be available on all page types (Master and UI)
public static class MessageHelper
{
public static void SetMessage(this Page page, String message)
{
Session["Message"] = message;
}
public static string GetMessage(this Page page)
{
var messageText = Session["Message"] as string;
if (!String.IsNullOrEmpty(messageText ))
{
Session["Message"] = "";
return messageText;
}
return "";
}
}
You could certainly use the query string to pass data to your List.aspx page, but be careful passing text that you're planning on writing out in the HTML - you'll need to protect against XSS attacks.
There are several other ways to do this. Chances are, you're going to have several places in your application where you want to redirect the user to another page, but also display a message that has something to do with what they did on the previous page (saved an item, deleted an item, etc.). It would be better to come up with more of a global scheme for this rather than a one-off just for this particular instance.
One idea is to use the Session for storing a message, then do your redirect.
Session("Message") = "Item was added to list."
Response.Redirect("List.aspx")
Then, on your pages (or a Master Page, perhaps), you check Session("Message") and if it's got something, you show that message to the user, then clear that variable.
If Session("Message") IsNot Nothing Then
Response.Write(CType(Session("Message"), String)) 'or set a label text, or show a pop up div, or whatever'
Session("Message") = Nothing
End If
If you use this approach, I recommend you write a helper class, and just use that to manage your messaging:
MessageHelper.SetMessage("Item added to list.")
and
MessageHelper.GetMessage()
would be the methods you would need.
I believe you could do it by setting the PostBackUrl of the button used to save the data to "List.aspx". Maybe set a variable to true/false on AddToList.aspx and then access it from List.aspx?
Not sure if it's better but it's an option.
I can't comment yet or I would have just commented this to your post. You need to cast your session variable like this: (string)Session["Message"]. So, code would look like this:
public class MessageHelper : System.Web.UI.MasterPage
{
public void SetMessage(String message)
{
Session["Message"] = message;
}
public string GetMessage()
{
if (String.IsNullOrEmpty((string)Session["Message"]))
{
String temp = (string)Session["Message"];
Session["Message"] = "";
return temp;
}
else
{
return "";
}
}
}
Actually there's a better way of writing that class: make it one property instead of two methods. It would look like this: (I also fixed your logic; GetMessage was always returning blank)
public class MessageHelper : System.Web.UI.MasterPage
{
public MessageHelper()
{
}
public string Message
{
set { Session["Message"] = value; }
get
{
if (String.IsNullOrEmpty((string)Session["Message"]))
{
Session["Message"] = "";
}
return (string)Session["Message"];
}
}
}
In your two respective files, you would set and get it like so:
//in AddToList.aspx
MessageHelper msg = new MessageHelper();
msg.Message = "The Item was added to your list.";
//and in List.aspx, assigned to an arbitrary Label named myMessageLabel
MessageHelper msg = new MessageHelper();
myMessageLabel.Text = msg.Message;
I am trying to make a validator that will make sure that at least 2 items are selected. The validator works correctly on the server side but the client side code never gets executed.
Here is the code:
Sys.Mvc.ValidatorRegistry.validators["country"] = function (rule) {
var min = rule.ValidationParameters["min"];
return function (value, context) {
if (value >= min) return true;
return rule.ErrorMessage;
};
};
And here is the validator code:
public class CountryValidator : DataAnnotationsModelValidator<CustomValidations.CountryAttribute>
{
private int _minimum;
private string _message;
public CountryValidator(ModelMetadata metadata, ControllerContext context, CustomValidations.CountryAttribute attribute) : base(metadata,context,attribute)
{
_minimum = attribute.Minimum;
_message = attribute.ErrorMessage;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = _message,
ValidationType = "country"
};
rule.ValidationParameters.Add("min", _minimum);
return new[] { rule };
}
}
I have even registered the validation adapter in global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(AgeAttribute), typeof(AgeValidator));
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CountryAttribute),typeof(CountryValidator));
}
I am thinking that the validator only works with the elements that have a value property like textboxes etc.
UPDATE 1:
EnableClientValidation is invoked correctly and all the required JS files are included in the project. It seems like I need to attach the onblur to the context. I will try that and post the results.
<% =Html.EnableClientValidation(); %> needs to be in your view somewhere. Also make sure you reference MicrosoftAjax.js and MicrosoftMvcValidation.js in the same view (before your js function).
Either your missing MicrosoftMvcAjax.js or you need to implement your custom validation in jQuery as described on Mr. Haack's website http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx.
I think it is because the default validation is invoked on the onblur event of the input textbox. And for a listbox this event was not being thrown.
The following test:
[TestClass]
public class MyTestClass
{
private TestContext _testContext;
protected TestContext TestContext
{
get { return _testContext; }
set { _testContext = value; }
}
[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/MyPage.aspx")]
public void TestMyPage()
{
TextBox tb = TestContext.RequestedPage.FindControl("ControlId") as TextBox;
Assert.IsNotNull(tb);
}
}
fails, and using the string "ctl00$ContentPlaceHolder1$ControlId" as control Id provide a proper control... I know, ASP.NET contains "ClientID" property for web-controls, but is there any possibility to know in advance the control's client Id in the TEST (Under VS 2008)?
Thanks.
I don't think the ClientID is what you're after here. I think your problem is that FindControl is not doing what you think it is.
FindControl is not recursive. If your textbox is inside of a ContentPlaceHolder, then you need to call FindControl on the placeholder, not the Page.
Otherwise, I suggest writing a recursive FindControl function that will search the entire control heirarchy. You can see an example here.
I'm looking for a best practice solution that aims to reduce the amount of URLs that are hard-coded in an ASP.NET application.
For example, when viewing a product details screen, performing an edit on these details, and then submitting the changes, the user is redirected back to the product listing screen. Instead of coding the following:
Response.Redirect("~/products/list.aspx?category=books");
I would like to have a solution in place that allows me to do something like this:
Pages.GotoProductList("books");
where Pages is a member of the common base class.
I'm just spit-balling here, and would love to hear any other way in which anyone has managed their application redirects.
EDIT
I ended up creating the following solution: I already had a common base class, to which I added a Pages enum (thanks Mark), with each item having a System.ComponentModel.DescriptionAttribute attribute containing the page's URL:
public enum Pages
{
[Description("~/secure/default.aspx")]
Landing,
[Description("~/secure/modelling/default.aspx")]
ModellingHome,
[Description("~/secure/reports/default.aspx")]
ReportsHome,
[Description("~/error.aspx")]
Error
}
Then I created a few overloaded methods to handle different scenarios. I used reflection to get the URL of the page through it's Description attribute, and I pass query-string parameters as an anonymous type (also using reflection to add each property as a query-string parameter):
private string GetEnumDescription(Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
return attr.Description;
}
}
return null;
}
protected string GetPageUrl(Enums.Pages target, object variables)
{
var sb = new StringBuilder();
sb.Append(UrlHelper.ResolveUrl(Helper.GetEnumDescription(target)));
if (variables != null)
{
sb.Append("?");
var properties = (variables.GetType()).GetProperties();
foreach (var property in properties)
sb.Append(string.Format("{0}={1}&", property.Name, property.GetValue(variables, null)));
}
return sb.ToString();
}
protected void GotoPage(Enums.Pages target, object variables, bool useTransfer)
{
if(useTransfer)
HttpContext.Current.Server.Transfer(GetPageUrl(target, variables));
else
HttpContext.Current.Response.Redirect(GetPageUrl(target, variables));
}
A typical call would then look like so:
GotoPage(Enums.Pages.Landing, new {id = 12, category = "books"});
Comments?
I'd suggest that you derive your own class ("MyPageClass") from the Page class and include this method there:
public class MyPageClass : Page
{
private const string productListPagePath = "~/products/list.aspx?category=";
protected void GotoProductList(string category)
{
Response.Redirect(productListPagePath + category);
}
}
Then, in your codebehind, make sure that your page derives from this class:
public partial class Default : MyPageClass
{
...
}
within that, you can redirect just by using:
GotoProductList("Books");
Now, this is a bit limited as is since you'll undoubtedly have a variety of other pages like the ProductList page. You could give each one of them its own method in your page class but this is kind of grody and not smoothly extensible.
I solve a problem kind of like this by keeping a db table with a page name/file name mapping in it (I'm calling external, dynamically added HTML files, not ASPX files so my needs are a bit different but I think the principles apply). Your call would then use either a string or, better yet, an enum to redirect:
protected void GoToPage(PageTypeEnum pgType, string category)
{
//Get the enum-to-page mapping from a table or a dictionary object stored in the Application space on startup
Response.Redirect(GetPageString(pgType) + category); // *something* like this
}
From your page your call would be: GoToPage(enumProductList, "Books");
The nice thing is that the call is to a function defined in an ancestor class (no need to pass around or create manager objects) and the path is pretty obvious (intellisense will limit your ranges if you use an enum).
Good luck!
You have a wealth of options availible, and they all start with creating a mapping dictionary, whereas you can reference a keyword to a hard URL. Whether you chose to store it in a configuration file or database lookup table, your options are endless.
You have a huge number of options available here. Database table or XML file are probably the most commonly used examples.
// Please note i have not included any error handling code.
public class RoutingHelper
{
private NameValueCollecton routes;
private void LoadRoutes()
{
//Get your routes from db or config file
routes = /* what ever your source is*/
}
public void RedirectToSection(string section)
{
if(routes == null) LoadRoutes();
Response.Redirect(routes[section]);
}
}
This is just sample code, and it can be implemented any way you wish. The main question you need to think about is where you want to store the mappings. A simple xml file could do it:
`<mappings>
<map name="Books" value="/products.aspx/section=books"/>
...
</mappings>`
and then just load that into your routes collection.
public class BasePage : Page
{
public virtual string GetVirtualUrl()
{
throw new NotImplementedException();
}
public void PageRedirect<T>() where T : BasePage, new()
{
T page = new T();
Response.Redirect(page.GetVirtualUrl());
}
}
public partial class SomePage1 : BasePage
{
protected void Page_Load()
{
// Redirect to SomePage2.aspx
PageRedirect<SomePage2>();
}
}
public partial class SomePage2 : BasePage
{
public override string GetVirtualUrl()
{
return "~/Folder/SomePage2.aspx";
}
}