I am having a number of panels in my page in which I am collecting user information and saving the page details. The page panel has textbox, dropdown list, listbox.
When I need to come to this page. I need to show the Page if these controls have any values. How to do this?
It boils down to enumerating all the controls in the control hierarchy:
IEnumerable<Control> EnumerateControlsRecursive(Control parent)
{
foreach (Control child in parent.Controls)
{
yield return child;
foreach (Control descendant in EnumerateControlsRecursive(child))
yield return descendant;
}
}
You can use it like this:
foreach (Control c in EnumerateControlsRecursive(Page))
{
if(c is TextBox)
{
// do something useful
}
}
You can loop thru the panels controls
foreach (Control c in MyPanel.Controls)
{
if (c is Textbox) {
// do something with textbox
} else if (c is Checkbox) {
/// do something with checkbox
}
}
If you have them nested inside, then you'll need a function that does this recursively.
I know this is an old post, and I really liked christian libardo's solution. However, I do not like the fact that in order to yield an entire set of elements to the outer scope I would have to iterate over those elements yet again only to yield those to myself from an inner scope to the current scope. I prefer:
IEnumerable<Control> getCtls(Control par)
{
List<Control> ret = new List<Control>();
foreach (Control c in par.Controls)
{
ret.Add(c);
ret.AddRange(getCtls(c));
}
return (IEnumerable<Control>)ret;
}
Which allows me to use it like so:
foreach (Button but in getCtls(Page).OfType<Button>())
{
//disable the button
but.Enabled = false;
}
Depeding on which UI library or language you are using, container controls such as panels maintain a list of child controls. To test if a form/page has any data you need to recursively search each panel for data entry controls such as text boxes. Then test if any of the data entry controls contain values other than default value.
A simpler solutions would be to implement an observer class that attaches to the changed events of your data controls. If the observer is triggered then your page has changes. You will need to take into consideration actions such as changing and then reverting data.
Very similar solution to Cristian's here, which uses recursion and generics to find any control in the page (you can specify the control at which to start searching).
http://intrepidnoodle.com/articles/24.aspx
Related
I have tried searching around for this, but what I found was mainly for disabling a single input type.
What I want to do is disable every input type on a single page. Everything. Textboxes, checkboxes the whole lot.
I couldnt figure out how to modify the loops I found, which is why I am asking here, beacause it's likely one of you has a piece of code laying around that can do it.
Thank you in advance.
try below if you like to do it in javascript/jquery
$(document).ready(function(){
$('input').attr('disabled','disabled');
});
OR try below if you want in asp.net
ach control has child controls, so you'd need to use recursion to reach them all:
protected void DisableControls(Control parent, bool State) {
foreach(Control c in parent.Controls) {
if (c is DropDownList) {
((DropDownList)(c)).Enabled = State;
}
DisableControls(c, State);
}
}
Then call it like so:
protected void Event_Name(...) {
DisableControls(Page,false); // use whatever top-most control has all the dropdowns or just the page control
} // divs, tables etc. can be called through adding runat="server" property
I'm simply trying to change all my RadTextBox borders to black. i'm sure the structure of my foreach loop is right, however i'm not able to find any RadTextBoxes.
I have a masterpage called master.Page and a childpage inheriting that page called child.aspx.
There is 10 radtextboxes on child.aspx, but i'm unable to find any, i've tried.....
foreach (var control in this.Controls.OfType<RadTextBox>())
{
control.BorderColor = System.Drawing.Color.Black;
}
foreach (var control in this.Page.Controls.OfType<RadTextBox>())
{
control.BorderColor = System.Drawing.Color.Black;
}
Since you've mentioned that you're using MasterPages. You''ll find the controls which are on top of your child aspx pages from master not via this.Controls but via contentPlaceHolder1.Controls since that is the NamingContainer.
If you would have other textboxes in child controls like FormView or GridView you woudn't even find them this way because Enumerable.OfType does not search recursively into child controls of a given control. You can try this recursive extension with OfType:
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
Use it in following way:
var allRadTextBoxes = this.Controls.Cast<Control>()
.Traverse(c => c.Controls.OfType<RadTextBox>());
foreach(var radTextBox in allRadTextBoxes)
{
radTextBox.BorderColor = System.Drawing.Color.Black;
}
The problem is because your control is not directly on the page. Your control is in a Form that is on the page.
foreach (var control in this.Page.Form.Controls.OfType<RadTextBox>())
{
control.BorderColor = System.Drawing.Color.Black;
}
You can either look for the Controls inside the form, or search recursively using Tim Schmelter approach
Would it be possible to create a control called say 'AbsolutePanel' that sets the position to 'absolute' for any controls placed on the panel ?
That will also work in VS2010 design time environment ??
Cristian Libardo posted some code which allows you to walk through all controls on a panel:
IEnumerable<Control> EnumerateControlsRecursive(Control parent)
{
foreach (Control child in parent.Controls)
{
yield return child;
foreach (Control descendant in EnumerateControlsRecursive(child))
yield return descendant;
}
}
You can use it like this:
foreach (Control c in EnumerateControlsRecursive(Page))
{
if(c is TextBox)
{
// do something useful
}
}
Could this be used to set the design time & runtime position attribute/property of all controls on the 'AbsolutePanel' ?
Just a thought.
It would make 'Application Form' style development similar to WPF/Winform for fixed size/dialogs/forms.
Any info appreciated.
Thanks
I'm doing a menu that loads levels dynamicly, when you click on a item the next level is loaded asynchronously. For each menu item I have a user control. Every user control is declared in its parent, for example, the "secondlevelcontrol" has the reference to "thirdlevelcontrol".
With this level of nesting, I want to manage the asynchronous calls on every user control so, when the first level is loaded the javascript to load the second is loaded too. When the second level is loaded the javascript to load the third is loaded too.
To do asynchronous calls I'm implementing ICallbackEventHandler interface. As you can see in the examples, controls are added to the page as plain html. The method "ProcessOnLoadEvent" executes all lines of the "OnLoad" event of the user control.
An example of the implementation is this for the user control of fourth level:
public string GetCallbackResult()
{
return _callbackRendering;
}
public void RaiseCallbackEvent(string itemId)
{
var id = Int32.Parse(itemId);
var menu = new LateralMenu();
var currentChildren = menu.GetNodesById(id, 1);
var ctrl = this.Page.LoadControl(USER_CONTROL_FIVE_LEVEL_RELATIVE_PATH) as LeftSideFifthLevel;
ctrl.Items = currentChildren.Children;
ctrl.ProcessOnLoadEvent();
_callbackRendering = ctrl.GetHtml();
}
And this is the code for the fifth level user control:
public void ProcessOnLoadEvent()
{
EnsureChildControls();
if (null != RepeaterMenu)
{
SettingCallbackReference();
Visible = null != Items && 0 < Items.Count;
if (null != Items && 0 < Items.Count)
{
RepeaterMenu.DataSource = Items;
RepeaterMenu.DataBind();
}
}
}
public void RaiseCallbackEvent(string itemId)
{
var id = Int32.Parse(itemId);
var menu = new LateralMenu();
var currentChildren = menu.GetNodesById(id, 1);
var ctrl = this.Page.LoadControl(USER_CONTROL_SIX_LEVEL_RELATIVE_PATH) as LeftSideSixthLevel;
ctrl.Items = currentChildren.Children;
ctrl.ProcessOnLoadEvent();
_callbackRendering = ctrl.GetHtml();
}
public void SettingCallbackReference()
{
var cm = this.Page.ClientScript;
var cbRef = cm.GetCallbackEventReference(this, "itemId", "AnchorLevel5_OnClick_Callback", "ctx");
var cbScript = "function AnchorLevel5_OnClick(itemId, ctx){ new Menu().empty(ctx); " + cbRef + "; }";
cbScript += "function AnchorLevel5_OnClick_Callback(htmlText, ctx){ new Menu().render(htmlText, ctx); }";
cm.RegisterClientScriptBlock(this.GetType(), "CallServer", cbScript, true);
}
My problem is that levels beyond second level never work because the javascript associated with the user control ("SettingCallbackReference" method) has no html to put on the page.
Is there any way to create some user controls created dynamicly that implements ICallbackEventHandler interface that add new user controls to the page? Or, Am I doing something wrong and this is not the right way to implement this behaviour?
Thanks!!!
I suspect that you are probably going about this the wrong way. Take a look at the answer to this question: How to lazy load Infragistics UltraWebTree control?
This question was specifically about lazy-loading a tree view, but the same principles apply for lazy loading menu items. Follow these steps:
On first page load, render the top level menu
Include a function on the page that makes an ajax call to the server with the
parent id and retuns the next level items for that parent (getNodes in my example)
Bind this function to the click event of the top level menu items (that have sub items)
In the success handler of the ajax call, inject the returned menu items below
the parent and bind the same function to the click event of these items only.
On callback, be careful not to bind the function to the click event of ALL menu items, because then you will end up getting the function bound multiple times to the top level items and called multiple times. Just bind to the returned items.
Also, you need some way of determining that an item's sub items have already been loaded. That is what the following line in my example was for, but you might need something slightly different:
if (jQuery(nodesDiv).text() == 'Loading...') {
I used jQuery because it is the most concise, but you culd do this in pure js - I wouldn't recommend it.
What is the trick to get the controls inside the FormView. I was getting them with FindControl() but, now i cant get access on them. Example: i have some ImageButton on the FooterTemplate, great i can get those smoothly, when it comes to the controls inside the FormView!!! null every control. Do you think i should name them differently in every template?
This gets me thinking about the table causing this noise!
I'm using the DataBound Event and checking for specific Mode! Any ideas? Thank you.
[UPDATED]
This is working
if (this.kataSistimataFormView.CurrentMode == FormViewMode.Edit)
{
ImageButton update = (ImageButton)this.kataSistimataFormView.FindControl("btnUpdate");
update.Visible = true;
But this for some reason no
CheckBox chkBoxPaidoi = kataSistimataFormView.FindControl("chkBoxPaidoi") as CheckBox;
FindControl is not recursive. What I mean is that it will only find controls that are within the child controls of the control you are searching - it will not search any child controls of the child controls
If you have placed the control you previously were looking for within another control then you will have to either search within that new control or, if you still want to use kataSistimataFormView as the parent control, you may have to use a recursive search.
Google for "findcontrol recursive" there are some good examples that you can probably just cut-and-paste.
As it seems this was caused because of the same naming ID's on various templates, Insert,Edit,Item. Even this is supported by the compiler, has problem when you are going for them programmaticaly later.
Thank you all.
Did you ever get this figured out? If you know the ID you can use this recursive function:
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
Found here:
http://www.codinghorror.com/blog/2005/06/recursive-pagefindcontrol.html