How to add both input and validation control from codebehind - c#

I am working within a CMS known as RiSE built in iMIS (I don't recommend)
I am building a plugin type thing which will allow the administrator from the backend of the program to build a contact form. (really simple right!?!?!?)
So, I don't know what, or how many form inputs will be present to process.
the process is for each added input
add its "id" to a list to be used when the form is submitted
build the input and add attributes based on administrator selected options
add the validator
The following code is the piece the adds the inputs to the page. The idea is simple, the administrator "creates" the input and chooses their options (name, label, placeholder, readonly, etc)
The codebehind would then take these options and build the input and corosponding input validation control.
I keep getting this error
Unable to find control id 'text_9d8f153' referenced by the 'ControlToValidate' property of 'val_9d8f153'.
here are the files;
EmailFormTextBoxDisplay.ascx
<%# Control Language="C#" AutoEventWireup="True" CodeBehind="EmailFormTextBoxDisplay.ascx.cs" Inherits="EmailForm.EmailFormTextBoxDisplay" %>
<%# Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<%# Register TagPrefix="asiweb" Assembly="Asi.Web" Namespace="Asi.Web.UI.WebControls" %>
<div onprerender="buildMe" runat="server"></div>
EmailFormTextBoxDisplay.ascx.cs
using System
...
protected void buildMe(object sender, EventArgs e)
{
HtmlGenericControl div = (HtmlGenericControl)sender;
if (EmailForm.formProcessed)
{
div.Visible = false;
}
else
{
String id = inputEmailLabel.Replace(" ", "-") + "_" + randId;
// add this input to the list
EmailForm.inputs.Add(new String[]
{
id,
inputType,
inputEmailLabel
});
// if label is not empty, add it
if (inputLabel != "")
{
HtmlGenericControl label = new HtmlGenericControl("label");
label.InnerText = inputLabel + " ";
label.TagName = "label";
div.Controls.Add(label);
}
// build and add the input
HtmlInputGenericControl input = new HtmlInputGenericControl("input");
// get each setting and add attributes to the input
input.Attributes.Add("type", inputType);
input.Attributes.Add("id", id);
input.Attributes.Add("placeholder", inputPlaceholder);
if (inputValue != "") input.Attributes.Add("value", inputValue);
if (inputDisabled) input.Attributes.Add("disabled", "disabled");
if (inputReadOnly) input.Attributes.Add("readonly", "readonly");
if (inputRequired)
{
input.Attributes.Add("required", "required");
AsiRequiredFieldValidator required = new AsiRequiredFieldValidator();
required.ControlToValidate = id;
required.ID = "val_" + randId;
required.Text = "This is Required";
div.Controls.Add(required);
}
if (inputRegEx != "" && inputRegEx != null)
{
AsiRegularExpressionValidator regEx = new AsiRegularExpressionValidator();
regEx.ValidationExpression = inputRegEx;
regEx.ControlToValidate = id;
regEx.ID = "regExVal_" + randId;
regEx.Text = inputRegExMsg;
div.Controls.Add(regEx);
}
div.Controls.Add(input);
}
}
I have tried breaking the validation part out into it's own method, and calling the first part (making the input) onLoad and then adding the validators onPreRender but I get the same error.
I also tried using Control.AddAt(2, input) to ensure the <input /> is before the validator, but to no avail.
How can I build an input & validation dynamically?

You need to use reference the ID generated by aspnet, not the one set by an Attribute. THis is because the ID will be renamed by aspnet client side, so the actual ID in html might become something like this ctl00_PlaceHolder1_myID
HtmlInputGenericControl input = new HtmlInputGenericControl("input");
input.ID = id;
and then the Validator
required.ControlToValidate = input.ID;
You could also use "real" aspnet Controls.
TextBox tb = new TextBox();
tb.ID = "myTextBox" + i;
RequiredFieldValidator val = new RequiredFieldValidator();
val.ControlToValidate = tb.ID;
val.ErrorMessage = "Required field";
Literal lit = new Literal();
lit.Text = "<br>";
PlaceHolder1.Controls.Add(tb);
PlaceHolder1.Controls.Add(val);
PlaceHolder1.Controls.Add(lit);

ControlToValidate requires the server side id of the control you want to validate. You will need to set the id of the control like this:
input.ID = "MY_ID";
Then use the inputs id to validate:
required.ControlToValidate = input.ID;

Related

Can I check a query string in an anchor tag before the anchor tag is clicked on the parent page? If so, how?

In my application FirstPage.aspx I am using a repeater to create a series of links:
<a href="MySecondPage.aspx?id=<%#DataBinder.Eval(Container.DataItem, "ValueID")%>">
<%#DataBinder.Eval(Container.DataItem, "ValueName")%></a>
Normally, in the page load of MySecondPage.aspx I would get the value of the QueryString like:
string OldID = Request.QueryString["id"];
num SkulloID = Convert.ToInt(SkulloID);
if(SkulloID > 5)
{
Response.Write("Hello World");
}
Instead of this, what I want to do is somehow on FirstPage.aspx get the value of the querystring in the anchor tag to do some logic on just as in the case of MySecondPage.aspx. Is something like this possible?
Edited to test solutions presented
#CodingBiz I tried the solution you presented and I am having trouble. Here is what I have tried.
In the Page_Load i added the following code to set the CommandArgument of the link button
//Error: The name containder does not exist in the current context
lbnTestLink.CommandArgument = DataBinder.Eval(container.DataItem, "ValueID");
In the asp:LinkButton click command
MyID = DataBinder.Eval(container.DataItem, "ValueID");
using (SqlConnection conn2 = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString))
{
SqlCommand cmdzero = new SqlCommand(#"SELECT [num] FROM [My_Table] Where [ValueID] = #MyID AND [IsSubItem] = 1 AND [FiscalYear] = #FiscalYear", conn2);
cmdzero.Parameters.AddWithValue("#MyID", MyID);
cmdzero.Parameters.AddWithValue("#FiscalYear", strFiscalYear);
conn2.Open();
int countzero = (int)cmdzero.ExecuteScalar();
int myArgument = countzero;
if (MyID = myArgument)
{
strListLink = "FistPage.aspx";
}
else
{
strListLink = "SecondPage.aspx?id=<%#DataBinder.Eval(Container.DataItem, \"ValueID\")%>";
}
}
I don't understand where the querystring is supposed to get set here.

Repetitive tasks on multiple pages?

Using C# with ASP.NET on an Intranet website. I've got multiple "Admin" pages where I'm checking fields to make sure a date is present, checking fields to make sure the Username is present and filling in those fields if they were left blank. On all of these pages, there exists fields with identical names. The block of code I'm using in the code-behind is below:
//If the User fields are empty, set them to the current user
string ActiveUser = System.Web.HttpContext.Current.User.Identity.Name;
string LoginID = ActiveUser.Right(6);
var txtLoadedBy_chk = string.IsNullOrEmpty(str5);
if ((txtLoadedBy_chk == true))
{
str5 = LoginID;
}
var txtUpdatedBy_chk = string.IsNullOrEmpty(str7);
if ((txtUpdatedBy_chk == true))
{
str7 = LoginID;
}
var txtFlgUpdatedBy_chk = string.IsNullOrEmpty(str9);
if ((txtFlgUpdatedBy_chk == true))
{
str9 = LoginID;
}
// If the date fields are NULL, set them to today's date
var txtLoadedOn_chk2 = string.IsNullOrEmpty(str6);
if ((txtLoadedOn_chk2 == true))
{
str6 = DateTime.Today.ToString();
}
var txtUpdatedOn_chk2 = string.IsNullOrEmpty(str8);
if ((txtUpdatedOn_chk2 == true))
{
str8 = DateTime.Today.ToString();
}
var txtFlgUpdatedOn_chk2 = string.IsNullOrEmpty(str10);
if ((txtFlgUpdatedOn_chk2 == true))
{
str10 = DateTime.Today.ToString();
}
// Check to make sure the dates entered are valid. If not, let the user know and
// then exit out of the code so the record is not saved
var txtLoadedOn_chk = DateTimeHelpers.IsValidSqlDateTimeNative(str6);
var txtUpdatedOn_chk = DateTimeHelpers.IsValidSqlDateTimeNative(str8);
var txtFlgUpdatedOn_chk = DateTimeHelpers.IsValidSqlDateTimeNative(str10);
if ((txtLoadedOn_chk == false) || (txtUpdatedOn_chk == false) || (txtFlgUpdatedOn_chk == false))
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "ch", "<script>alert('WARNING !! One of your date fields is invalid')</script>");
return;
}
I'm thinking that since I do the EXACT same checks on all of these forms, I should be able to put this block of code somewhere and just reference it, instead of putting it in every form. How would I go about doing that? If I put it in a separate page or CS file, how will it know which form is calling it so it reads the proper fields? If you can provide some sample code, that would be a huge help. TIA!
Oh, and DateTimeHelpers is a class I created, in case you're wondering.
EDIT: I just want to be clear on something; this code is in the code-behind and is called when the user presses the "Save" button. It's just verifying the data before it tries to write it to the SQL Server table.
What you want to do here is create a user control. You can add one of those to your project with the "New File" stuff Visual Studio provides. I will call that user control Fields.ascx in this answer.
The code in your answer goes in the code-behind for that user control (Fields.ascx.cs). The form elements that you have on every page go in Fields.ascx.
Once you do that, you reference the user control at the top of your page like this:
<%# Register TagPrefix="user2174085" TagName="MyFields" Src="~/Path/To/Fields.ascx" %>
And then you add the fields to your page in the right place with the following code:
<user2174085:MyFields runat="server" />
In the <%# Register %> portion, you can make the TagPrefix and TagName pretty much anything you want, just make sure they match when you use the control.
You could always write a public method in a cs file and pass your controls as reference variables. Here is a quick example of what that could look like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
namespace mol_intranet
{
public class ClassTesting
{
//pass the fields to be checked/updated here as ref variables
public void checkFields(ref TextBox loadedby, ref TextBox updatedby)
{
string ActiveUser = System.Web.HttpContext.Current.User.Identity.Name;
string LoginID = ActiveUser.Right(6);
var txtLoadedBy_chk = string.IsNullOrEmpty(loadedby.Text);
if ((txtLoadedBy_chk == true))
{
loadedby.Text = LoginID;
}
var txtUpdatedBy_chk = string.IsNullOrEmpty(updatedby.Text);
if ((txtUpdatedBy_chk == true))
{
updatedby.Text = LoginID;
}
}
}
}
Then just call the method in your code and pass your controls:
ClassTesting t = new ClassTesting();
t.checkFields(txtLoadedBy, txtUpdatedBy);
Hope this helps.

usercontrol template system c#

I want to use string replace to replace the tag {tag:shoppingcart} and in that it would load the user control:
<%# Register TagPrefix="basket" TagName="cart" src="~/controls/basket.ascx" %>
<basket:cart id="test" runat="server"></basket:cart>
I would be defining the controls at the top of the page that needs them.
My question is what is my best way to achieve the following if it is at all possible
string templatehtml;
templatehtml = template[0].Cms;
string newhtml;
newhtml = templatehtml.Replace("{tag_pagecontent}", currentPage[0].Body);
newhtml = templatehtml.Replace("{tag_shoppingcart}", <basket:cart id="test" runat="server"></basket:cart>);
litcontent.Text = newhtml;
It's the <basket:cart code i am having trouble with.
We actually do a very similar thing, except we have placeholder divs on the page.
In the page_init method, we get a reference to the placeholder div, load the user control into the page, and then add the usercontrol to the div's controls.
For example (very rough code):
// Get a reference to the div
Control oUserControlDiv = this.FindControl("divUserControl");
// Load the user control
Control oControl = this.LoadControl("controls/basket.ascx");
oControl.EnableViewState = true;
// Clear the existing control(s) from the div
oUserControlDiv.Controls.Clear();
// And add the new one
oUserControlDiv.Controls.Add(oControl);
Please try this instead:
var basket = new Basket();
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (HtmlTextWriter writer = new HtmlTextWriter(sw))
{
basket.RenderControl(writer);
}
string basketHtml = sb.ToString();
newhtml = templatehtml.Replace("{tag_shoppingcart}", basketHtml);

Javascript works on IE but not on Firefox and gives me error as Error: cprofiledetailscollapse is not defined

I use C#.net.
I wrote JavaScript for hide and show expand and collapse div accordingly. It work well in IE but not on Firefox, not even call the JavaScript function and gives me error as Error: ctl00_cpContents_dlSearchList_ctl08_profiledetailscollapse is not defined.
My JavaScript is as follows
function displayDiv(divCompact, divExpand) {
//alert('1');
var str = "ctl00_cpContents_";
var divstyle = new String();
// alert("ibtnShowHide" + ibtnShowHide);
divstyle = divCompact.style.display;
if (divstyle.toLowerCase() == "block" || divstyle == "") {
divCompact.style.display = "none";
divExpand.style.display = "block";
// ibtnShowHide.ImageUrl = "images/expand_img.GIF";
}
else {
// ibtnShowHide.ImageUrl = "images/restore_img.GIF";
divCompact.style.display = "block";
divExpand.style.display = "none";
}
return false;
}
ctl00_cpContents_dlSearchList_ctl08_profiledetailscollapse is an element id generated by ASP.NET. It's a profiledetailscollapse control inside dlSearchList.
JavaScript variable "ctl00_cpContents_dlSearchList_ctl08_profiledetailscollapse" is not
defined. Firefox does not automatically create, for each element with an id, a
variable in the global scope named after that id and containing a reference
to the element.
You might want to consider using jQuery to make sure that your DOM manipulation is cross-browser compatible.

C# WebBrowser control not applying css

I have a project that I am working on in VS2005. I have added a WebBrowser control. I add a basic empty page to the control
private const string _basicHtmlForm = "<html> "
+ "<head> "
+ "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> "
+ "<title>Test document</title> "
+ "<script type='text/javascript'> "
+ "function ShowAlert(message) { "
+ " alert(message); "
+ "} "
+ "</script> "
+ "</head> "
+ "<body><div id='mainDiv'> "
+ "</div></body> "
+ "</html> ";
private string _defaultFont = "font-family: Arial; font-size:10pt;";
private void LoadWebForm()
{
try
{
_webBrowser.DocumentText = _basicHtmlForm;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and then add various elements via the dom (using _webBrowser.Document.CreateElement). I am also loading a css file:
private void AddStyles()
{
try
{
mshtml.HTMLDocument currentDocument = (mshtml.HTMLDocument) _webBrowser.Document.DomDocument;
mshtml.IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet("", 0);
TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"basic.css"));
string style = reader.ReadToEnd();
styleSheet.cssText = style;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is the css page contents:
body {
background-color: #DDDDDD;
}
.categoryDiv {
background-color: #999999;
}
.categoryTable {
width:599px; background-color:#BBBBBB;
}
#mainDiv {
overflow:auto; width:600px;
}
The style page is loading successfully, but the only elements on the page that are being affected are the ones that are initially in the page (body and mainDiv). I have also tried including the css in a element in the header section, but it still only affects the elements that are there when the page is created.
So my question is, does anyone have any idea on why the css is not being applied to elements that are created after the page is loaded? I have also tried no applying the css until after all of my elements are added, but the results don't change.
I made a slight modification to your AddStyles() method and it works for me.
Where are you calling it from? I called it from "_webBrowser_DocumentCompleted".
I have to point out that I am calling AddStyles after I modify the DOM.
private void AddStyles()
{
try
{
if (_webBrowser.Document != null)
{
IHTMLDocument2 currentDocument = (IHTMLDocument2)_webBrowser.Document.DomDocument;
int length = currentDocument.styleSheets.length;
IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet(#"", length + 1);
//length = currentDocument.styleSheets.length;
//styleSheet.addRule("body", "background-color:blue");
TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "basic.css"));
string style = reader.ReadToEnd();
styleSheet.cssText = style;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is my DocumentCompleted handler (I added some styles to basic.css for testing):
private void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement element = _webBrowser.Document.CreateElement("p");
element.InnerText = "Hello World1";
_webBrowser.Document.Body.AppendChild(element);
HtmlElement divTag = _webBrowser.Document.CreateElement("div");
divTag.SetAttribute("class", "categoryDiv");
divTag.InnerHtml = "<p>Hello World2</p>";
_webBrowser.Document.Body.AppendChild(divTag);
HtmlElement divTag2 = _webBrowser.Document.CreateElement("div");
divTag2.SetAttribute("id", "mainDiv2");
divTag2.InnerHtml = "<p>Hello World3</p>";
_webBrowser.Document.Body.AppendChild(divTag2);
AddStyles();
}
This is what I get (modified the style to make it as ugly as a single human being can hope to make it :D ):
one solution is to inspect the html prior to setting the DocumentText and inject CSS on the client side. I don't set the control url property but rather get the HTML via WebCLient and then set the DocumentText. maybe setting DocumentText (or in your case Document) after you manipulate the DOM could get it to re-render properly
private const string CSS_960 = #"960.css";
private const string SCRIPT_FMT = #"<style TYPE=""text/css"">{0}</style>";
private const string HEADER_END = #"</head>";
public void SetDocumentText(string value)
{
this.Url = null; // can't have both URL and DocText
this.Navigate("About:blank");
string css = null;
string html = value;
// check for known CSS file links and inject the resourced versions
if(html.Contains(CSS_960))
{
css = GetEmbeddedResourceString(CSS_960);
html = html.Insert(html.IndexOf(HEADER_END), string.Format(SCRIPT_FMT,css));
}
if (Document != null) {
Document.Write(string.Empty);
}
DocumentText = html;
}
It would be quite hard to say unless you send a link of this.
but usually the best method for doing style related stuff is that you have the css already in the page and in your c# code you only add ids or classes to elements to see the styles effects.
I have found that generated tags with class attribute does not get their styles applied.
This is my workaround that is done after the document is generated:
public static class WebBrowserExtensions
{
public static void Redraw(this WebBrowser browser)
{
string temp = Path.GetTempFileName();
File.WriteAllText(temp, browser.Document.Body.Parent.OuterHtml,
Encoding.GetEncoding(browser.Document.Encoding));
browser.Url = new Uri(temp);
}
}
I use similiar control instead of WebBrowser, I load HTML page with "default" style rules and I change the rules within the program.
(DrawBack - maintainance, when I need to add a rule, I also need to change it in code)
' ----------------------------------------------------------------------
Public Sub mcFontOrColorsChanged(ByVal isRefresh As Boolean)
' ----------------------------------------------------------------------
' Notify whichever is concerned:
Dim doc As mshtml.HTMLDocument = Me.Document
If (doc.styleSheets Is Nothing) Then Return
If (doc.styleSheets.length = 0) Then Return
Dim docStyleSheet As mshtml.IHTMLStyleSheet = CType(doc.styleSheets.item(0), mshtml.IHTMLStyleSheet)
Dim docStyleRules As mshtml.HTMLStyleSheetRulesCollection = CType(docStyleSheet.rules, mshtml.HTMLStyleSheetRulesCollection)
' Note: the following is needed seperately from 'Case "BODY"
Dim docBody As mshtml.HTMLBodyClass = CType(doc.body, mshtml.HTMLBodyClass)
If Not (docBody Is Nothing) Then
docBody.style.backgroundColor = colStrTextBg
End If
Dim i As Integer
Dim maxI As Integer = docStyleRules.length - 1
For i = 0 To maxI
Select Case (docStyleRules.item(i).selectorText)
Case "BODY"
docStyleRules.item(i).style.fontFamily = fName ' "Times New Roman" | "Verdana" | "courier new" | "comic sans ms" | "Arial"
Case "P.myStyle1"
docStyleRules.item(i).style.fontSize = fontSize.ToString & "pt"
Case "TD.myStyle2" ' do nothing
Case ".myStyle3"
docStyleRules.item(i).style.fontSize = fontSizePath.ToString & "pt"
docStyleRules.item(i).style.color = colStrTextFg
docStyleRules.item(i).style.backgroundColor = colStrTextBg
Case Else
Debug.WriteLine("Rule " & i.ToString & " " & docStyleRules.item(i).selectorText)
End Select
Next i
If (isRefresh) Then
Me.myRefresh(curNode)
End If
End Sub
It could be that the objects on the page EXIST at the time the page is being loaded, so each style can be applied. just because you add a node to the DOM tree, doesnt mean that it can have all of its attributes manipulated and rendered inside of the browser.
the methods above seem to use an approach the reloads the page (DOM), which suggests that this may be the case.
In short, refresh the page after you've added an element
It sounds as though phq has experienced this. I think the way I would approach is add a reference to jquery to your html document (from the start).
Then inside of the page, create a javascript function that accepts the element id and the name of the class to apply. Inside of the function, use jquery to dynamtically apply the class in question or to modify the css directly. For example, use .addClass or .css functions of jquery to modify the element.
From there, in your C# code, after you add the element dynamically invoke this javascript as described by Rick Strahl here: http://www.west-wind.com/Weblog/posts/493536.aspx

Categories