I hope someone knows the answer to this as I am very new to using Telerik controls. Here is the problem, I have a requirement that says that I have to set the background color for a control attached to a validation control if the IsValid flag was set on the validation control. An earlier requirement that I had may be affecting this as well, it was set focus to the control based on the SetFocusOnError="true".
All of the controls are contained in a asp:UpdatePanel and the page has a master page set.
So what I have done is the following to set focus I overrode the Validate function on the System.Web.UI.Page class as so:
public override void Validate(string group)
{
base.Validate(group);
// get the first validator that failed
var validator = GetValidators(group)
.OfType<BaseValidator>()
.FirstOrDefault(v => !v.IsValid);
// set the focus to the control
// that the validator targets
if (validator != null)
{
//Check to see if SetFocusOnError was set.
if (validator.SetFocusOnError == true)
{
Control target = validator
.NamingContainer
.FindControl(validator.ControlToValidate);
if (target != null)
target.Focus();
}
}
}
This works and sets focus to the control. The next thing that I did was the following inline in my webpage:
var OriginalValidatorUpdateDisplay = null;
if (typeof (ValidatorUpdateDisplay) == 'function') {
OriginalValidatorUpdateDisplay = ValidatorUpdateDisplay;
ValidatorUpdateDisplay = NewValidatorUpdateDisplay;
}
function NewValidatorUpdateDisplay(val) {
OriginalValidatorUpdateDisplay(val);
ValidateControls();
}
function ValidateControls() {
if (window.Page_Validators) {
for (var vI = 0; vI < Page_Validators.length; vI++) {
var vValidator = Page_Validators[vI];
if (vValidator.isvalid) {
$("#" + vValidator.controltovalidate).removeClass("error");
if ($("#" + vValidator.controltovalidate).parent().find('.riTextBox').length > 0) {
$("#" + vValidator.controltovalidate).parent().removeClass("error");
}
}
else {
$("#" + vValidator.controltovalidate).addClass("error");
if ($("#" + vValidator.controltovalidate).parent().find('.riTextBox').length > 0) {
$("#" + vValidator.controltovalidate).parent().addClass("error");
}
}
}
}
}
However, when you load the page and submit the page for validation the first time the css doesn't change, but if you do it again it does. Oh and the AddClass is just adding
.error .riTextBox
{
background-color: lightpink !important;
z-index:6001;
}
to the control.
Has anyone worked encountered this before?
Oh I should also note that if I remove the Telerik controls and use asp textbox controls everything works as it should but I can't remove the Telerik controls from the project.
Related
I extended the ASP.NET CheckBoxList web control to create a Bootstrap 5 layout version.
The control works fine, but on postback, it loses the checked state. Also, the control's SelectedItem property is null.
I created the same control for the RadioButtonList and it works perfectly. Using DotPeek, I see that both of those inherit the same controls and interfaces, so I can't figure out why the custom RadioButtonList maintains state but the CheckboxList doesn't.
Any ideas? The internet has no useable examples to speak of.
C#
public class Bootstrap5CheckBoxList : CheckBoxList {
protected override void Render(HtmlTextWriter writer) {
try {
var selected = false;
//var webControl = new WebControl(HtmlTextWriterTag.Div);
//webControl.ID = ClientID;
//webControl.RenderBeginTag(writer);
for (int index = 0; index < Items.Count; index++) {
var item = this.Items[index];
//div
writer.Indent++;
writer.WriteBeginTag($"div class='form-check {base.CssClass}'");
writer.Write('>');
writer.WriteLine();
//input
writer.Indent++;
writer.WriteBeginTag("input");
writer.WriteAttribute("id", $"{this.ID}_{index}");
writer.WriteAttribute("type", "checkbox");
writer.WriteAttribute("name", $"{this.UniqueID}_{index}");
var cssClass = "";
if (item.Attributes["class"] != null) {
cssClass = item.Attributes["class"];
}
writer.WriteAttribute("class", $"form-check-input {cssClass}");
writer.WriteAttribute("value", item.Value);
var clientID = this.ClientID;
if (item.Selected) {
if (selected) {
this.VerifyMultiSelect();
}
selected = true;
writer.WriteAttribute("checked", "checked");
}
if (item.Attributes.Count > 0) {
foreach (string key in item.Attributes.Keys) {
if (!"class".Equals(key)) {
writer.WriteAttribute(key, item.Attributes[key]);
}
}
}
if (!item.Enabled)
writer.WriteAttribute("disabled", "disabled");
if (this.Page != null) {
this.Page.ClientScript.RegisterForEventValidation(
this.UniqueID,
item.Value);
}
writer.Write('>');
writer.WriteEndTag("input");
writer.WriteLine();
//label
writer.WriteBeginTag("label");
writer.WriteAttribute("class", "form-check-label");
writer.WriteAttribute("for", $"{this.ID}_{index}");
writer.Write('>');
HttpUtility.HtmlEncode(item.Text, writer);
writer.WriteEndTag("label");
writer.Indent--;
writer.WriteLine();
//Close Div
writer.WriteEndTag("div");
writer.WriteLine();
writer.Indent--;
}
//webControl.RenderEndTag(writer);
} catch (Exception ex) {
throw new Exception(string.Format("{0}.{1}:{2} {3}", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName, System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message, ex.StackTrace));
}
}
}
HTML
<%# Register TagPrefix="BSControls" Namespace="My.App.classes.custom_controls" Assembly="My.App" %>
<BSControls:Bootstrap5CheckBoxList ID="customCheckList" runat="server">
<asp:ListItem Value="1">Check 1</asp:ListItem>
<asp:ListItem Value="2">Check 2</asp:ListItem>
</BSControls:Bootstrap5CheckBoxList>
looks like you now using html controls, and they don't have automatic viewstate. you would be MUCH better to use a CheckBox list, and format that with bootstrap. And it also FAR better to include that checkbox list in the user control markup, and not write code to inject such controls if possible.
So, plain jane check box (input type = checkbox) as a general rule does not have automatic view state like asp.net controls. So, either drop in a check box list into your user control markup, or you may well have to add code to save/restore the values, since it looks much like you are injecting the "input" control as opposed to using a asp.net checkbox list.
After many trials, I was able to get this working and the answer is surprisingly, or maybe not, simple.
The 'name' attribute is the key and must be in the correct format.
Incorrect Format
writer.WriteAttribute("name", $"{this.UniqueID}_{index}");
Correct Format
writer.WriteAttribute("name", $"{this.UniqueID}${index}");
You must use the $ separator and not an underscore. On postback, the LoadPostData method in CheckBoxList iterates through a collection to retrieve the check state.
In the ascx.cs file I'm dynamically generating buttons. In .aspx file I add the control to the form. The control itself renders well, but when the buttons are clicked I get this error
An error has occurred because a control with id 'ctl03' could not be
located or a different control is assigned to the same ID after
postback.
DestopControl.ascx.cs
public partial class DesktopControl : PlaceHolder
{
public void Build()
{
for (int i = 0; i < 10; i++)
{
Button button = new Button()
{
Width = 50,
Height = 50,
ID = string.Format("button{0}", i),
Text = i.ToString()
};
button.Click+=new EventHandler(button_Click);
}
}
}
Default.aspx.cs
DesktopControl desktop = new DesktopControl();
desktop.Build();
MainContent.Controls.Add(desktop);
After reading the comments (little hard to read the code-part of the comments) it appears that yes, you are generating your controls inside an if(!isPostBack){}; well, looks like it's in the else part of that if statement.
You have to generate your controls every time the page posts back, as the page_load gets fired before your button click. So once the controls have been re-created the code will continue on to your button click handler, where the controls should be available to handle.
Essentially, take ReloadUI(Session["ui"]); OUT of the if(!isPostBack){}else{} statement. Put it after your if statement.
Like this:
if (!isPostBack){
// my first load code
}else{
// my postback code
}
// load all my dynamic controls here
ReloadUI(Session["ui"]);
Found a solution:
Every time there is a new UI I call this ClearScreen() which does the trick.
The error on 'ctl03' was a menu control which was generating it's own ID and somehow wasn't available on postback. I assigned an ID to it. But I guess all the issue went away with this ClearScreen() method.
private void ClearScreen()
{
try
{
List<Control> controls = new List<Control>();
foreach (Control control in MainContent.Controls)
{
controls.Add(control);
}
for (int i = 0; i < controls.Count; i++)
{
if (!(controls[i].GetType() == typeof(LiteralControl) || controls[i].GetType() == typeof(ScriptManager)))
{
MainContent.Controls.Remove(controls[i]);
}
}
}
catch (Exception ex)
{
}
}
I have four controls in a page with update panel. Initially mouse focus is set to first control. When I partially post back the page to server the focus automatically moves to first control from the last focused control from the control I have tabbed down to. Is there any way to maintain the last focus?
Take a look at Restoring Lost Focus in the Update Panel with Auto Post-Back Controls:
The basic idea behind the solution is to save the ID of the control
with input focus before the update panel is updated and set input
focus back to that control after the update panel is updated.
I come with the following JavaScript which restores the lost focus in
the update panel.
var lastFocusedControlId = "";
function focusHandler(e) {
document.activeElement = e.originalTarget;
}
function appInit() {
if (typeof(window.addEventListener) !== "undefined") {
window.addEventListener("focus", focusHandler, true);
}
Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(pageLoadingHandler);
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(pageLoadedHandler);
}
function pageLoadingHandler(sender, args) {
lastFocusedControlId = typeof(document.activeElement) === "undefined"
? "" : document.activeElement.id;
}
function focusControl(targetControl) {
if (Sys.Browser.agent === Sys.Browser.InternetExplorer) {
var focusTarget = targetControl;
if (focusTarget && (typeof(focusTarget.contentEditable) !== "undefined")) {
oldContentEditableSetting = focusTarget.contentEditable;
focusTarget.contentEditable = false;
}
else {
focusTarget = null;
}
targetControl.focus();
if (focusTarget) {
focusTarget.contentEditable = oldContentEditableSetting;
}
}
else {
targetControl.focus();
}
}
function pageLoadedHandler(sender, args) {
if (typeof(lastFocusedControlId) !== "undefined" && lastFocusedControlId != "") {
var newFocused = $get(lastFocusedControlId);
if (newFocused) {
focusControl(newFocused);
}
}
}
Sys.Application.add_init(appInit);
I find this more elegant:
(function(){
var focusElement;
function restoreFocus(){
if(focusElement){
if(focusElement.id){
$('#'+focusElement.id).focus();
} else {
$(focusElement).focus();
}
}
}
$(document).ready(function () {
$(document).on('focusin', function(objectData){
focusElement = objectData.currentTarget.activeElement;
});
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(restoreFocus);
});
})();
I know how to enable/disable individual validator controls on the client side using
ValidatorEnable(validator, false);
But how do you enable/disable all the validators within a ValidationGroup?
The validator properties aren't rendered as attributes unfortunately, so I don't know a good way to select them directly. You can try to iterate the Page_Validators array and filter out the ones you want to work with.
Try:
$.each(Page_Validators, function (index, validator){
if (validator.validationGroup == "your group here"){
ValidatorEnable(validator, false);
}
});
Check this blogpost explaining how with javascript. The main part of the code from the blog:
<script type="text/javascript">
function HasPageValidators()
{
var hasValidators = false;
try
{
if (Page_Validators.length > 0)
{
hasValidators = true;
}
}
catch (error)
{
}
return hasValidators;
}
function ValidationGroupEnable(validationGroupName, isEnable)
{
if (HasPageValidators())
{
for(i=0; i < Page_Validators.length; i++)
{
if (Page_Validators[i].validationGroup == validationGroupName)
{
ValidatorEnable(Page_Validators[i], isEnable);
}
}
}
}
</script>
Alternatively you can simply have ValidationGroup attribute with each validator defined .
Then you wont need any Jquery or javascript stuff to close them.
Here is the link that worked for me.
http://www.w3schools.com/aspnet/showasp.asp?filename=demo_prop_webcontrol_imagebutton_validationgroup
What I am trying to do is accessing Page Controls at Page_Load, and make a database query, and make controls visible or not visible.
Here is the Code:
foreach (Control thiscontrol in ContentPlaceHolderBody.Controls) {
try {
if (thiscontrol.ID.Contains("TextBox") || thiscontrol.ID.Contains("Label")) {
string dummy = thiscontrol.ID;
bool IsValid = db.Roles.Any(a => a.controlName == dummy);
if (IsValid == false)
thiscontrol.Visible = false;
}
else if (thiscontrol.ID.Contains("UpdatePanel")) {
foreach (Control UPcontrols in ((UpdatePanel)thiscontrol).ContentTemplateContainer.Controls) {
if (UPcontrols.ID.Contains("TextBox") || UPcontrols.ID.Contains("DropDownList")) {
bool UPIsValid = db.Roles.Any(a => a.controlName == UPcontrols.ID);
if (UPIsValid == false)
UPcontrols.Visible = false;
}
}
}
}
catch { }
}
My Problem is with the UPcontrols! It should retrieve the controls within the UpdatePanel, but the thing is it doesn't do its job, except in the debug mode!
When I add a breakpoint, everything is OK, but when I run the web application, it doesn't find any components within the UpdatePanel...
Try this one:
ControlCollection cbb = updatepanel1.Controls;
ControlCollection cb = cbb[0].Controls;
initialize_Controls(cb);
public void initialize_Controls(ControlCollection objcontrls)
{
foreach (Control tb in objcontrls) {
if (tb is TextBox)
((TextBox)tb).Text = "";
if (tb is Panel) {
ControlCollection cbcll = tb.Controls;
foreach (Control tbb in cbcll) {
if (tbb is TextBox)
((TextBox)tbb).Text = "";
}
}
}
}
First find controls from updatepanel i.e ContentTemplate, then find controls from contentTemplate which contain all controls in it.
This seems like a very bizarre design. That is, using control IDs for such purposes is rather unusual.
Nevertheless, you need a recursive method here to do a deep walk of every control on the page. Your method will not work if the UpdatePanel is contained within another control.
Have a check on this article
http://www.codeproject.com/Articles/24178/The-magical-effects-of-the-UpdatePanel-control-in