ASP.NET find all Controls on a page and hide them - asp.net

I'm trying to on Page_Load hide all my RadioButtonLists but I can't seem to get the syntax quite right
I'm guessing I've got to use the FindControl syntax something like this
CType(FindControl, RadioButtonList)
And then I'm guessing I will have to loop through each RadioButtonList and set the Visible = False attribute on it.
I seem to be getting an error with the code above.
Any ideas what I can try?
Thanks

Try this:
protected void Page_Load(object sender, EventArgs e)
{
HideRadioButtonLists(Page.Controls);
}
private void HideRadioButtonLists(ControlCollection controls)
{
foreach (WebControl control in controls.OfType<WebControl>())
{
if (control is RadioButtonList)
control.Visible = false;
else if (control.HasControls())
HideRadioButtonLists(control.Controls);
}
}

FindControl only works if you know the name of the control you're looking for, and more than that it is not a recursive call. Unless you can guarantee that your control will be in the specific container you're searching in, you won't find it. If you want to find all of the radiobutton lists, you'll need to write a method that cycles through all control sets in the parent/child relationship and sets the radiobuttonlist visible to false.
Just pass Page.Controls to this function (untested, may need tweaking):
public void HideRadioButtonLists(System.Web.UI.ControlCollection controls)
{
foreach(Control ctrl in controls)
{
if(ctrl.Controls.Count > 0) HideRadioButtonLists(ctrl.Controls);
if("RadioButtonList".Equals(ctrl.GetType().Name, StringComparison.OrdinalIgnoreCase))
((RadioButtonList)ctrl).Visible = false;
}
}

Why not use a ASP.Net skin page to set the default values for all RadioButtonLists to visible = false.
I would def look into using a skin page here.

Doing a foreach on the Controls property and checking the type is going to be slow. What you should be doing, in my opinion and depending on your requirements, is using CSS / skins to hide the unwanted buttons or simply adding them to a List<T> so you can loop through only those that you need to modify.
Worst case scenario the foreach will work but it’s a bit slow and undesirable.

Related

Identifying all asp:Image controls in code behind

I am trying to find all asp:Image controls in the vb.net code behind to dynamically set the ImageUrl to the same image file. This I can do seperately for each control, but writing 10+
imgQuestion.ImageUrl = cdn.Uri.ToString & "images/question.png" lines seems a little silly. I do not need to skip any image controls - every single one on the page will be changed. Is there any way to identify all of them without specifying each ID?
The IDs are not all named something similar, such as "Image1", "Image2" but rather "PaymentNote", "search", etc so I cannot loop through all the numbers with something like FindControl("Image" & controlNumber)
Is there another way to do this? I'd prefer to keep the image control IDs as something meaningful.
You can recursively use FindControl, starting from the Page and for each control check if it's an <asp:Image...
My own preferred language of choice is C#, so I won't be able to show a VB example. But here's a C# example:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ChangeImageUrls(Page);
}
private void ChangeImageUrls(Control ctrl)
{
foreach (Control subCtrl in ctrl.Controls)
{
if (subCtrl is Image)
{
((Image)subCtrl).ImageUrl = "...";
}
if (subCtrl.HasControls())
ChangeImageUrls(subCtrl);
}
}
}

asp.net treeview programmatically setting node color

I want to set the node colors of a treeview at runtime. I populate the treeview from a collection that has the parentid, childid, and description, and I've added a property representing the color I want applied to the node. FWIW the source is a database, the app is C#.
In a gridview I use RowDataBound() to programmatically affect the control. Im not sure how to do so in the treeview, including which event to use (DataBound()? TreeViewDataBound()?). My research has not been fruitful so far. A code snippet would be very useful.
Hopefully this will give you a raging clue.
When setting a node text, instead of setting
Node Text
set as
<div style='color: red'>Node Text</a>
you can use Prerender event:
protected void TreeView1_PreRender(object sender, EventArgs e)
{
if (IsPostBack) return;
foreach (TreeNode t in TreeView1.Nodes)
{
if (t.Value.EndsWith("1")) //Some Condition
{
string s = t.Text;
string fs = "<span style=\"color: #CC0000\">" + s + "</span>";
t.Text = fs;
}
}
}
Since .NET Framework 4.5 you can use these style properties:
TreeView.LevelStyles Property - represent the node styles at the
individual levels of the tree
TreeView.RootNodeStyle Property
TreeView.ParentNodeStyle Property
TreeView.LeafNodeStyle
Property
Assuming you are dealing with the standard TreeView control, you can do this in the TreeDataBound Event.
A brief example (not tested):
<asp:TreeView runat="server"
ID="tvMyTreeView"
OnTreeNodeDataBound="tvMyTreeView_TreeNodeDataBound"
/>
And the backend:
protected void tvMyTreeView_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
DataRowView dr = (DataRowView)e.Node.DataItem;
e.Node.Style.Add("color", dr["COLOR"].ToString());
}
If you are using the Telerik RadTreeView, then the event name is NodeDataBound
You will probably have to tweak the example to better fit your needs, but hopefully this will get you started.

ASP.NET Triggering server-side events with multiple arguments

I've got a rather lengthy question I'm afraid. I'm fairly new to ASP.NET so please bear with me.
I have built a control for an ASP.NET page that lists a number of options. Each option has two clickable areas (call them buttons for the sake of simplicity). One to select the option and one to hide the option.
protected void Page_Load(object sender, EventArgs e)
{
RenderOptions();
}
public void RenderOptions()
{
for (int i = 0; i < 5; i++) {
HtmlGenericControl div1 = new HtmlGenericControl("div");
div1.Attributes.Add("onclick", ClientScript.GetPostBackEventReference(this, "option" + i));
m_TreeContainer.Controls.Add(div1);
HtmlGenericControl div2 = new HtmlGenericControl("div");
div2.Attributes.Add("onclick", ClientScript.GetPostBackEventReference(this, "option" + i));
m_TreeContainer.Controls.Add(div2);
}
}
public void RaisePostBackEvent(string arg)
{
//do something
}
This works fine (I do implement the IPostBackEventHandler interface). The problem here is that there doesn't seem to be a way for me to find which HTML element was clicked and thus which action should be performed in the RaisePostBackEvent method.
What I tried to do is create a new class (HtmlDivControl) which looks like this:
class HtmlDivControl : HtmlGenericControl, IPostBackEventHandler
{
#region Delegates
public delegate void ClickEventHandler(object sender, string eventArgument);
#endregion
#region Properties
private ClickEventHandler m_Click;
public ClickEventHandler Click
{
get { return m_Click; }
set { m_Click = value; }
}
#endregion
#region Constructors
public HtmlDivControl()
{
}
#endregion
public void RaisePostBackEvent(string eventArgument)
{
m_Click.Invoke(this, eventArgument);
}
}
Now I made div1 and div2 my HtmlDivControl rather than HtmlGenericControl, set the Click property to a method (delegate) and passed the div (div1 or div2) itself as control for the GetPostBackEventReference method. This time, I could not only differentiate between the divs but also pre-determine the action that should be performed. However, the RaisePostBackEvent for controls are called after PageLoad. So the problem I'm with now is that the whole options control is rendered before the events are handled (and thus, an option that should for instance be hidden isn't because the actual hiding happens after the rendering). Moving the RenderOptions() call to the PageLoadComplete method doesn't help either, since then the div controls won't exist yet.
I'm pretty sure I'm missing something quite fundamental here. But could someone please explain me how I should approach something like this?
p.s.
How am I supposed to write underscores here? They're used to make text italic? Is there some escape character?
For someone new to ASP.Net, you've done pretty well so far. Your roadblock here is actually the way you are thinking about the issue. You should get a good grasp of the ASP.Net Page Lifecycle - you are missing something very fundamental.
In a nutshell, you want your page to rebuild it's state to the same way it was before the postback. Then process your events. Then make any state changes.
You're thinking about it as if your html controls should know about their state change at the start of the request, which is incorrect. There has to be the rebuilding phase first. This is critical for ASP.Net to even figure out which events to raise.
What I would recommend:
move your "RenderOptions()" method to the Page_Init handler. This will save you lots of issues if you ever incorporate ViewState into your controls. (I would also rename it, as it's not truly rendering anything, it's just adding your controls to the page. Render has a specific context in ASP.Net).
Then, in your OnClick event handlers for your controls, simply set your controls visibility as necessary, rather than trying to control the way they are rendered. It is always much simpler to set controls to Visible=False rather than try to change the way the controls are being rendered to the page. Remember that if you set Visible=False, there will be zero html sent to the response for that control, but the server will still know it's on the page, so you can still deal with it.
Think about your event handlers as the place where you will change the state of the page. It's where your logic should be in this case, rather than in Page_Load.

Forcing ASP.NET GridView's pager to show

is there some way to force the gridview's pager to show up, even when there is only one page of data on screen?
I'm building a gridview-based control with a custom pager (w/dropdown for pagesize) and everything is working fine, except when user selects pagesize that is larger than the current row count of the grid. At that point the pager disappears. I've been googling this and i think that i should be doing something in override OnRowCreated...
Custom pager is added by overriding InitializePager. I'll be glad to provide more information if required!
greets,
J.Arola
Ok, that wasn't too hard :-)
Based on my initial testing the following did the trick:
GridViewRow pagerRow = (GridViewRow) this.BottomPagerRow;
if(pagerRow != null && pagerRow.Visible == false)
pagerRow.Visible = true;
I just added that to overridden OnPreRender, and lo, pager is visible, even when there is just one page page of data shown. Got to do some additional testing before I can be sure, though. Seems to simple to me.
The above will work
But this might be helpful also
GridView.BottomPagerRow.Visible=true
protected void GridView_PreRender(object sender, EventArgs e)
{
GridView gv = (GridView)sender;
GridViewRow pagerRow = (GridViewRow)gv.BottomPagerRow;
if (pagerRow != null && pagerRow.Visible == false)
pagerRow.Visible = true;
}
GridView.BottomPagerRow.Visible=true works like a charm

Default to last page in a ListView

Using a standard ASP.NET ListView with a LinqDataSource and pagination enabled (with a DataPager), what would be the best way to default to displaying the last page of results?
set the current page index to be the page count - 1.
You'll need to know the total record count and the number of records displayed on a page.
This helpful post shows you how to get the record count:
private LinqDataSourceSelectEventArgs args;
protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
args = e;
e.Result = new Database().Table.Whatever...
}
protected void LinqDataSource1_Selected(object sender, LinqDataSourceStatusEventArgs e)
{
this.label1.Text = args.Arguments.TotalRowCount + " records";
}
There's further discussion there of a situation that sounds similar to yours.
I've never done this, but there are several places I would look to see if I could make the change you want: an OnSelecting handler for the data source, OnPreRender or OnDataBinding for the ListView, and OnPreRender for the DataPager. Essentially, you want to handle the case of !IsPostBack in a special way. I would probably look at the DataPager first and see if you can find out how many pages there are and set it to the last page. You may need to rebind the data source after setting the page to the one you want. After that I'd look at adding an OnDataBinding handler for the ListView and see what you can do there. I suspect that PreRender happens too late for the ListView to have any effect and OnSelecting, while good for filtering via a table-based function, probably won't do much good in this case.

Resources