Treeview asp.net - c#

I have a treeview control on an asp.net page. Everytime I select a node in the tree, a duplicate copy of the tree is displayed under it. I am unable to understand. I have not written any code so far. I'm probably missing out on some property that I should have set. No matter which node I click on another tree is displayed under the existing tere. Please help!

It sounds like you're adding the Treeview to the page on Page_Load without testing if it's a Postback or not.
If it's a Postback then the Treeview will be automatically added to the page as the WebForm reconstructs itself.
Try this:
void Page_Load() {
if( !Page.IsPostback ) {
// code to add treeview to page
}
}
That said - I strongly advice staying away from the WebForms Treeview control (and generally speaking, anything in the System.Web.UI.WebControls namespace - except for Literal and PlaceHolder) because they take away too much control from the developer and often end up wrecking the user experience. The WebControls library was originally designed around IE6, many years ago.
If you're starting a new project I strongly recommend you take a look at ASP.NET MVC instead.

Related

Dealing with multiple "chained" postbacks from dynamically-created controls in a single page

I'm trying to build a very specific search page for a project and I'm having lot of trouble dealing with multiple postbacks invoked by dynamically-generated controls on a single page.
The page has to work like this:
There is a single checkbox, "Detailed search", that causes a postback on checking/unchecking.
When detailed search is not active, a simple grid with contents and buttons is displayed. Nothing special.
When detailed search is active, N checkboxes must be generated from some dynamic data, that represent the sections where you want the search to happen. Below the checkboxes, an AJAX-enabled tab control will appear, initially with no tab pages.
When checking one of the section checkboxes, a postback will occur. After the postback, data will be searched in the section selected by the user, then a new tab page containing a grid view of results and the name of the section will be added to the tab control. If the checkbox is unchecked, the tab page will disappear from the control, again, after a postback.
Now, the issue is that pretty much everything has to be generated dynamically, and that pretty much everything is connected to something else.
First issue: dealing with the "Detailed search" checkbox. Sounds easy, doesn't it? My initial idea was to set Page.Viewstate["DetailedSearchEnabled"] to true or false during the check/uncheck event handler, then create controls dynamically checking the value of DetailedSearchEnabled during Page_Load.
Nope. The postback event-handling happens between Page_Load and Page_LoadComplete. It would take an additional refresh for things to work as intended.
<< Then I'll just generate the controls on Page_LoadComplete! >>
Nope. Those controls need event handling as well, and if they're generated after Page_Load they will not be wired up correctly.
A possible solution would be generating everything in advance, on Page_Load, and only hiding/showing controls on Page_LoadComplete. But that is inefficient, and one important point of this search page is that only the minimum amount of controls should be generated.
The difficulty of this task seems to come from the way event wiring and the page life cycle work.
Surely there must be a better way of approaching this problem.
First issue: dealing with the "Detailed search" check box.
The correct approach (if you want to use page post-backs) is as follows:
In the CheckChanged event handler, save the value of the Checked property to ViewState["DetailedSearchEnabled"]. If the value is true, add the dynamic check boxes to the page. If the value is false, find and remove them.
Override LoadViewState. After calling base.LoadViewState, re-create the dynamic check boxes and wire up their events if ViewState["DetailedSearchEnabled"] is true. Note that neither Page_Load nor Page_LoadComplete is the appropriate place to do this.
Yes, you should create the dynamic check boxes at two points in the page life cycle. I recommend a helper method.
In general, your event handlers should add or remove just the dynamic controls (if any) affected by those particular events, but LoadViewState should re-create all dynamic controls that existed from the previous page request. You must store enough information in view state for LoadViewState to do so.
My answer to this other question demonstrates how to add and remove dynamic controls. You may want to use it as a reference.
Sounds to me like you should be using a CheckBoxList control to handle your dynamic checkboxes. You can add an remove items to the CheckBoxList during your post back and not have to worry about dynamically adding/removing actual controls/events to the form.
Here is a link to the msdn:
https://msdn.microsoft.com/en-us/library/14atsyf5(v=vs.85).aspx
Here is some sample code:
Protected void Button1_Click (object sender, System.EventArgs e)
{
CheckBoxList.Items.Add(new ListItem("TextValue1", "Value1"));
CheckBoxList.Items.Add(new ListItem("TextValue2", "Value2"));
}
If all else fails, you could still fall back on the quick-and-dirty old-fashioned ASP way.
Use Response.Write or <%...%> to generate your dynamic controls as plain old HTML (simple form fields, e.g. <input type="checkbox" name="foo" value="1" />).
Make sure you have a form field for every piece of information you may need after the postback(s). If necessary, use hidden form fields to 're-post' values across subsequent postbacks.
After postback, retrieve the values of the controls with the Request object.
Use those values to adjust the generation of controls as you see fit.
You should be able to do all of this in Page_Load. The advantage is total freedom. The disadvantage is total freedom to make a big mess of your aspx. So you may want to migrate all this dirty code out of your aspx, and into a custom-made control, which you can then add to your aspx.
When generating your own HTML, be careful not to introduce XSS vulnerabilities. Use HtmlEncode where necessary.
As you suggested yourself, there is a better way to tackle it.
If I was in the same situation, I would create web methods for interacting with the page, and use client side to do the UI. I'm currently working mostly with angular JS, although it does come with a learning curve. You could use ng-hide/ng-show to bind to the checkbox event to display the detailed search. When the n number of checkboxes needs to be displayed, you can then just fill them in with ng-repeat, for each of the items you need to display, after a check/uncheck you can dynamically populate new controls etc. through web method calls if extra data is needed.
Pure ASP postbacks are quite clunky from my experience, and not really suited for building a maintainable dynamic UI.
Instead of making so many postbacks, it would be better to use jquery and ajax calls to load the controls as needed and then attach events to it or you can even use UpdatePnael for that. Help Links:
https://www.simple-talk.com/dotnet/asp.net/ajax-basics-with-jquery-in-asp.net/
http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/

Avoiding making duplicate panels of controls?

I'm making a web application, but I am not using MVC.
I have pages like: create a task, create a project, create a case...
Everyone of these requests standard information like: StartDate ( a calendar widget, etc), Start time, etc.
If, somewhere down the line, I need to change this standard stuff, say, I need to change the calendar for a textbox, I want it to change everwhere where this is used.
What is a proper way to do this sort of thing?
In the ASP .NET code it would be nice to have like:
SchedulePanel.Calendar.Date;
It does not have to be panel based or anything, but I basically have a group of controls that I need in many places.
Thanks
You can put all of those controls into a UserControl and add that whenever it is needed. Like Robert said, if it is needed on virtually every page, then put those controls into the master page.
asp.net UserControls are really idea for this type of situation.
http://asp.net-tutorials.com/user-controls/using/
Please explain more this statement:I want it to change everwhere where this is used.
If I undesrstand correctly you can put all your controls in a User Control and in code behind declare public variable and change your controls in set section

Creating dynamic UI in ASP.NET web forms

I need to create a survey page with the following structure read from database.
Survey QuestionA
a) Answer1 [Radio button]
b) Answer2 [Radio button]
c) Answer3 [Radio button]
d) Answer4 [Radio button]
repeats..
The page has many questions that needs to be dynamically added. I need to store the result of the form on in an array of Question object on submit.
One way I know to do this is create dynamic UI in a table and get the values by FindControl.
Is there a better (elegant) way to do this?
In ASP.Net MVC it handles the dirty work for you with default model binders. Of course you can also create your own. Though this does not give you the automatic solution you were hoping for in ASP.Net Web Forms, my preference in this situation would be to follow a similar common pattern that ASP.Net MVC is using for it's naming convention thus simplifying it. You could then start writing code that could be reused over time. Here is a link to an article explaining the naming convention on Haack's blog
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx.
Long term recommendation is to come to ASP.Net MVC, life is just better here :)
I suggest create a userconrol that implement a question(label) and answers(radio buttons) and each controls(labels,radios) is binded to a property of your usercontrol, Then you can read questions from database and for each data create this usercontrol object and set correspond data to that property of usercontrol, And to read data from control this state doing vice versa.
Albeit you must recreate usercontrols in each post back and set default data to those.
Also you can create multiple usercontrols with different UI that inherit a interface such as IQuestion, and a factory class that create each of usercontrols depend of environment varibles.
You can use jQuery to get the selected radio buttons by the checked property and append them with the question number.
e.g. for question 1 you have
So you can get the values iterating throught the radio buttons like so:
$("input[type='radio']").checked
You could always add the controls in programmatically.
Say you have a aspnet Panel control you can perform...
RadioButton rb = new RadioButton();
rb.ID = "rbRadioButton";
rb.Name = "rbRadioButton";
rb.cssClass = "radioClass";
Panel1.Controls.Add(rb);
Excuse the harshness of the example, not got visual studio to hand at the moment to check it but I hope you get the idea. You could in essence build up the whole question this way based purely on the database. The downside is getting the values as you have to override the Render method (if I remember right, it has been a while, I do have an example if you want me to find it).
I admit it is a little overkill but it is a possible solution.
use radiobuttonlist (which you can see in the the toolbox ,it is a asp.net standard control) control for this purpose. It is up to your needs.

When to use PreRender over PageLoad?

Related question: Get All Web Controls of a Specific Type on a Page
In the question above I asked how I can get all controls, works like a charm but something just doesn't quite fit so I thought it might be me. I have the following code but it's not manipulating the controls on the page but in my theory it should work.
List<DropDownList> allControls = new List<DropDownList>();
ControlEnhancer.GetControlList<DropDownList>(Page.Controls, allControls);
foreach (DropDownList childControl in allControls)
{
foreach (ListItem li in childControl.Items)
{
li.Attributes.Add("title", li.Text);
}
childControl.Attributes.Add("onmouseover", "this.title=this.options[this.selectedIndex].title");
}
Thats the code, GetControlList() code you can get from the related question which shows how it gets all controls, its just my manipulation. I am trying to get all dropdownlist listitems and add a title to them so I can have a tooltip.
It's a quick fix for IE8 and below which cuts of long text in drop down boxes.
Page_Load happens often too soon; Page_PreRender is the last moment before the page's HTML is actually rendered for the browser and in many cases is the best place to set attributes on user controls.
This because during the web form (page) life cycle there are other events in the page (and in the user controls contained in the page...) which sometimes remove/replace/overwrite (really) those attributes so the only way you can get those attributes to the browser is to append them after all other life cycle events have been fired and handled, in the Page_PreRender.
Actually, even PreRender might be too early in some cases (e.g. you could have DropDownList controls added to the control tree during databinding of controls that use DataSourceID).
There are two further events that might be more appropriate:
PreRenderComplete. At this point, all controls are created and the page is ready to render.
SaveStateComplete. Occurs after view state and control state have been saved. Any changes you make here won't be persisted to view state.
In your example (adding client-side attributes), I'd use the SaveStateComplete event to avoid unnecessary view state bloat.

How do I add events to nested server controls? (ASP.Net)

I am building a custom master page type control i.e. sort of like a datagrid but should be easier to add custom functionality into it. It's going great but part of the desired functionality is to have a paging control that switches on and off and part of that control would be a textbox that displays the current page number and on TextChanged redirects to the new page of the dataset.
The problem I'm having is that technically the textbox which has its event fired is embedded in a control that is embedded in the control you actually put on the page sort of like
Page
|
Display Control
|
Paging Control
|
Textbox
Buried all the way down there the event is not firing. Worse the postback javascript isn't even being written onto the page (Nothing on the page posts back so far this is the only bit that really needs to).
I've been trawling around Google for quite a while now and picked up that I need to implement INamingContainer (done) and I need to add the control into the page's control tree (is Pre_Init too late for that? When's a good time to Add the Control to the page?) then the event should fire, apparently. But I've been unable to find an example of best practice on this there are quite a few near misses where people are having button angst but this isn't a button.
So can anyone point me in the direction of getting a control embedded in a control embedded in a control added to a page to behave properly?
You need INamingContainer only if you plan to add more than one instance of your custom control to the same page. What it does is enabling unique id generation so you don't end up with controls with the same ID. I recommend you inherit from CompositeControl when creating your custom control.
Pre_Init is not too late. Actually it is pretty early considering the lifecycle. You can instantiate custom controls and add them to the live controls collection in a lot of places. I would recommend you do it in Page_Init (before viewstate is loaded) or Page_Load(after view state is loaded). Even if you add it later in the page lifecycle the control will catch up in events.
To subscribe to events of child controls you can use the FindControl method:
MyControl myControl = Page.FindControl("MyControl1");
TextBox textBox = myControl.FindControl("TextBox1") as TextBox;
The answer was a combination of the above answer and the comment on the original question. The vital thing to get the event to happen is to make sure that your controls (parent and child) inherit from CompositeControl and INamingContainer e.g.
public partial myControl:CompositeControl,INamingContainer
etc...
Then you override your composite control's CreateChildControls() method and create your controls and do the wire up there. This will ensure correct bubbling. and mean that the event handling takes place within your comoposite control...

Categories