Here is my scenario and I would like to ask your opinion on which control is best to use. I am using C#, ASP.net 2.0.
I am required to create a structure that resembles a tree. The user will start with something and then will add nodes to it. Every node is a structure by itself, so a user should be presented with an option to create a new node type or use an existing type of a node.
The obvious choice here seems TreeView. However, I have few concerns:
1) I was asked to minimize the number of trips back to the web server, and I am not sure how this would work with TreeView.
2) If I do end up using TreeView, creating a new node type (currently it is a .ascx (user control)) could be tricky to deal with, as I would need to open a new window and return node id and name to the parent page (which contains TreeView ) upon node type creation and seemlessly update it.
Any recommendations?
You may want to look into JQuery's Treeview
http://docs.jquery.com/Plugins/Treeview/treeview#options
this way, you can update the treeview on the client side, and when the user gets everything working as needed, then submit the tree state.
JQuery for .Net
http://jquerydotnet.codeplex.com/
Related
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.
I want to show the expand option against a tree node even if the node has no children. Is this possible?
(The expand option being the little plus sign in a box to the left of the node.)
If your purpose is to dynamically load children nodes when expanding the best solution is to add a fake child nodes to all the leaf nodes. Then replace the fake node with real ones when needed.
Try it with property TreeNode.PopulateOnDemand = true; - this is ideal for dynamically created trees and it adds plus sign icon also to node with no children.
Sorry this is not a direct answer to your question, but I do feel it is relevant.
Why would you want to do this? It is confusing for the user.
(I have just been through exactly the same process in another environment and user feedback was "This item is broken and won't let me see what's underneath like the other ones do").
In short, I would recommend evaluating the requirement carefully before you proceed.
A winform forms.cs contains a gridview. This gridview(many columns) get populated with an xml elements and its attributes.
Another class "XMLReader.cs" that reads XML file and returns
List <someclassObjects>
Now I am sending gridview as a parameter from form.cs to another class "UpdateAppUI.cs" that receives the Gridview as parameter and update it.
Question is: Is there any issues with passing controls as parameter? Experienced professionals said donnnn't pass controls.
Then How I can access form controls to other classes?
What is the solution for above situation?
why you want to pass the grid view?
If simply you want to update it in UpdateAppUI.cs file then pass the datafrom gridview in the datatable. And from datatable you can update the database from the class.
No need to pass the control.
If you really want to pass the datagrid then create new object of datagrid as same as yours and pass that as an parameter.
I think that what those developers are refering to is: avoid making your UI unrepsonsive. You might want to look at your design ( read: conceptual model / design diagram ) before your deside how to implement this functionality.
There's an article on MSDN covering "Give .NET Apps a Fast and Responsive UI with Multiple Threads".
Consider this, if you have a Parent form that needs to update its child controls you might want to make the whole form accessable by the "update helper". But then again, try not to make to much heavy lifting on the UI Thread.
Also remember that your controls are Objects and when Objects are passed as parameters they are sent as reference types so another "danger" is that your method might do something malicious to your control.
To make the design understandable and manageable by others as well, I would step back one step and think about the design of your software.
My plan is to create a a two-pane page using ASP MVC 3. The left pane should be a small filter pane and the right the main content, showing a list of objects (say products).
Initially all products will be shown since no filter is applied. When selecting "only red", only red products are shown in the list. When further selecting a price range, only products in that price range will be shown.
Functionally the plan is to implement the filtering pane as a treeview with checkboxes (to be able to drill down to more and more specific filtering options), graphically it will probably be enhanced in some way to improve usability.
What is the best way to implement the coupling between the filter pane and the main list? Everything should work server side, but should of course use javascript (jQuery) when possible for direct feedback.
The simplest way is probably to make it closely coupled solution, calling a specific Asp MVC action using a custom-built javascript (with fallback to a form post). Doable enough, sure, but how to make the solution reusable? Also it would be nice to not loose all filtering data when navigating forward and back, i suppose GET arguments is the only decent way to do that?
Are there any best practices, any guidelines or anything to base this on to make a nice modular structure for filtering.
Victor, I recently had to solved this same problem. I'm not promising it's the best way but it's pretty clear and should even work well in case JavaScript is disabled (who even does that anymore?).
Create a that calls the action with all the field-selectable search options like "only red".
To that same form, add empty, hidden value for the things not directly as fields (paging, sorting...)
Setup your form with the excellent and very easy to use JQuery.Forms (http://www.malsup.com/jquery/form/) to make you form submit via JQuery (all your form values will be passed as JSON on form submit).
Make your back/next/paging/sorting links pass their individual values via query (no-JS fallback) and use JQuery to capture their click events. The JQuery click events on those links should assign the value of the value passed by the link (page number, sort column name...) to the corresponding hidden field in the form and call submit (with thanks to Jquery.Forms will submit via AJAX).
When you configure JQuery.Forms, you can define a callback method. In the callback method take the result (the HTML returned by your action that should contained your filtered+sorted+paged result) and replace the document (or DIV if you used a partial action + view) with that.
The result is a JQuery solution that works when JS is off. You also have very minimal JS code to write other than wiring the event handlers.
I'm not sure if it will be helpful but in MVC 3 you have access to a property called IsAjax from the view so you can do specific things to server a slightly different view when called from AJAX.
Cheers
I have a legacy application that is written in C# and it displays a very complex treeview with 10 to 20 thousand elements.
In the past I encountered a similar problem (but in C++) that i solved with the OWNERDATA capability offered by the Win32 API.
Is there a similar mechanism in C#?
EDIT: The plan is to optimize the creation time as well as browsing time. The method available through Win32 API is excellent in both of these cases as it reduce initialization time to nothing and the number of requests for elements are limited to only the ones visible at any one time.
Joshl: We are actually doing exactly what you suggest already, but we still need more efficiency.
One technique for improving performance is to load TreeNodes as the user expands the treeview. Normally a user will not require 20,000 nodes to be open on their screen at once. Only load the level that the user needs to see, along with whatever child information you need to properly display affordances to the user (expand icon if children exist, counts, icons, etc). As the user expands nodes, load children just in time.
Helpful hint from Keith: With the winforms TreeView you need to have at least one child node or it won't show the expand [+], but then you handle the TreeNodeExpanded event to remove that dummy node and populate the children.
In our main WinForm app, we have a treeview loaded all in one shot:
BeginUpdate()
Load 20.000 nodes
EndUpdate()
and so far the performance is still nice. It is actually one of the few components we are not replacing with third party ones.
The TreeView performance, in my experience, gets slow when you load nodes (in one shot, or on demand) without calling Begin/EndUpdate(), especially if your nodes are sorted, but if you call Begin/EndUpdate() correctly, you shouldn't really get performance issues related to the component itself.
I don't believe the .NET TreeView supports what you want, although this type of model is supported by .NET's DataGridView (see DataGridView's VirtualMode property). The TreeView will let you draw your own nodes but it won't let you populate them from some virtual store.
If possible, you might want to consider the use of a DataGridView for your application. If not, managing the nodes manually (like joshl mentions above) might work if you can get around some issues with refreshing the screen properly when nodes are expanded. Outside of that, you might want to check out some of the third party vendors, like this one (Divelements SandGrid), that might (emphasis on might) support your desired mode of operation.
NOTE: The SandGrid is not supported by Divelements as of the end of July 2013.
NOTE: This answer is invalidated by an edit by the questioner saying he already does this kind of thing, but I decided to still post it for future reference by others searching on this topic
When I've done similar things in the past, I've tended to opt for the naive lazy-loading style.
Use the TreeNode.Tag property to hold a reference that you can use to look-up the children
Use the TreeView.BeforeExpand event to populate the child nodes
Optionally use the TreeView.AfterCollapse event to remove them.
To get the [+]/[-] boxes to appear, the best way I've found is to create a singleton dummy TreeNode that gets added as a child to all unpopulated Nodes, and you check for its existence before populating with BeforeExpand.
There is one way to make the TreeView perform much better and that is to create all sub-nodes and hook them together and then add the nodes to the TreeView. If it's the graphical performance we are talking about.
TreeView tree = new TreeView();
TreeNode root = new TreeNode("Root");
PopulateRootNode(root); // Get all your data
tree.Nodes.Add(root);
Otherwise, load them node by node using OnTreeNodeExpanded.
For large data in Windows C# programming, whether it be in WPF or WinForms, I have traditionally added nodes dynamically. I load the initial tree root + children + grandchildren deep. When any node is expanded, I load the tree nodes that would represent the grandchildren of the expanding node, if any.
This pattern also works well with data retrieval. If you are truly loading data from a source of thousands or millions of records you probably don't want to load those all up front. No user wants to wait for that to be loaded, and there is not reason to load data that may never be viewed.
I have typically loaded the grandchildren or the great-grandchildren node data as needed on a background thread, then marshal those data back to the UI thread and create and add the nodes. This leaves the UI responsive. You can visually decorate tree nodes to indicate they are still loading for the case where a user gets ahead of your IO to the data store.
This works for me (CSharp):
Visible = false;
...
Visible = true;
In my case(2000 nodes), it takes only 1~2 seconds to load the tree, which is much more quicker than any other ways.
It might work well in C++.