Is there a better way to access deeply nested controls? - asp.net

I've started work at a company and don't have full access to their previously built objects/frameworks/etc and I've been tasked with creating a new system, using their libraries / objects / etc. I can override most of their libraries, but without seeing what exactly is going on I'm finding it challenging to work with.
It is all in .net webforms, which I'm really not all that familiar with as well.
They have a customs Model-View-Controller sort of system built on top of webforms, which generates full control ascx pages, however of course the ascx file is simply one line, the code behind is empty, so all I can really see is the markup dynamically generated.
I will have markup written like:
<div id="id1">
<div id="id2">
<div id="id3">
<table id="tt_id1">
<input id="myModelNameID">
etc, etc.
The objects as well are named differently in .net vs what's generated in the markup, so this makes things even more challenging - I have to always examine the objects for a while to find the full path of where my control is located.
What is the easiest way to access a deeply nested control?
I've tried to use references to different ID's (like ClientID vs ID), etc. I have found examples here and there but usually people are doing something like what I'm doing.
I'm trying to avoid writing 30 findControls , etc. I could write a method I suppose that would do this, but I'm hoping there's an easier way even or something already available.
When I am trying to access anything in code-behind to access objects I am examining them in the debugger or using a dumper class or reflection, and then writing something like this:
//This is an example that would add a button in a table.
Button MyButt = new Button();
MyButt.Text = "Click Me";
//Split into sections for readability...
Control c = Page.FindControl("ctl00").FindControl("Form1");
Control c2 = c.FindControl("MainPage").FindControl("id1");
Control MyTable = c2.FindControl("id2").FindControl("myTable1");
MyTable.Controls.Add(MyButt);

Related

VS2008/ASP.NET 3.5 - How to create dynamic webforms

The question in a nutshell: Is there a way to add forms dynamically to a aspx-page? I know how to add controls to an existing form, but how to add a whole form?
Bckground:
I am "forced" to work in Visual Studio 2008 and I want to create a controller, which builds a page depending from the list of elements a model gives it (e.g.: the list may contain a paragraph, an image, another paragraph, a parapgraph again, a form and so on).
This works fine for the first examples as I am able to add them to the inner-html of a div-container.
Thinking about ways to generate a form like this (innerHTML += form), I feel I'd be throwing the few possible advantages ASP I can see (compared to PHP) out of the window in terms of input validation and so on. But I can't find a way to generate a "real, server-run" form. The same goes for gridviews, but I guess the solution may be similar.
A possible workaround would be to create an empty form
<form runat="server" id="dummyForm">...
and add controls to it dynamically. The obvious(?) downside to this would be, that I couldn't change its position (at least I wouldn't know how) in relation to the other content elements.
Another downside would be that I would be limited to one form per page and that may or may not be sufficient. If it wasn't I would starting to add several empty dummy-forms and would start indexing them and all of that doesn't look very cool to me.
Is there a more elegant way to a solution?
TIA
Simon
You can't add more than once server side Form tag in single aspx file
(in run time or design time)
maybe this article help you to generate dynamic forms :
https://msdn.microsoft.com/en-us/library/aa479330.aspx

Code Behind No Longer finds ID tags

I've been working on a website for several months now and am nearing my deadline. I know my methods are a little dated. Especially considering I still use tables. I've actually moved in a direction away from that, but this project is being produced from an excel spreadsheet and with more than 200 fields, it seems reasonable and the person I'm creating this for was happy to see the recreation.
Nevertheless, I am having an issue where I have declared an id for an asp TableCell and am trying to assign text to it. In the past this has worked. Literally every other page I have built has been able to accept this code.
Initially I had a textbox named "depthSingleUnit." With new data coming in, I realized I could combine the depth, height, and width information into one cell. And because I don't want the user to edit this data any longer, just view the information that's already available, I dropped the idea of using a textbox and just used the tablecell to display the information.
The tablecell now has an id "dimensionsSingleUnit"
<asp:TableCell columnspan="1" id="dimensionsSingleUnit"></asp:TableCell>
The code behind reads
dimensionsSingleUnit.Text = PONDS.Tables(0).Rows(0).Item("ProductDimensions")
Yet I get the error
Error 3 'dimensionsSingleUnit' is not declared. It may be inaccessible due to its protection level. C:\Users\aking\My. Documents\Visual Studio 2012\Projects\lampSpecs\lampSpecs\Factories\view.aspx.vb 289 4 lampSpecs
Am I missing something here? I have tried changing the id. I've tried creating a new tableCell with the same name. Tried creating a new tableCell with a different name. I tried creating a new file, but still have the same issue. I've tried re-building the project. I literally copy and paste the id into my code behind and that does not work.
The old ids from when I was using multiple cells for the data are still available, but all of the new ones that I've added will not display in intellisense and displays an error.
you need to add runat="server" to your html element to get access it from code page. because only runat="server" are available on the code behind page
Sorry meant to add as an answer....
Try
dimensionsSingleUnit.InnerHtml = PONDS.Tables(0).Rows(0).Item("ProductDimentiond")
I've not worked with tables cells in this way normally use gridviews or repeaters. It may be that a runat="server" for the table element is enough... but usually you need it for any html elements to be accessible from code

Add an Html Control in multiple parents in asp.net

I'm creating a new unordered list as follows:
Using htmlUL As New HtmlGenericControl("ul")
End Using
Before closing the 'Using' clause, the list has to be added in a parent control:
Using htmlUL As New HtmlGenericControl("ul")
'Some Code Here
parent1.Controls.Add(htmlUl)
End Using
Everything works fine until i add my control to more parents :
Using htmlUL As New HtmlGenericControl("ul")
'Some Code Here
parent1.Controls.Add(htmlUl)
parent2.Controls.Add(htmlUl) '<--- Only gets added in the last parent's collection
End Using
This behaviour is expected because every control is unique. But i need to add this list to more than one parents (it does not include any static ids in order to avoid conflicts)
ASP.NET does not support scenario like the very same control object used in several places. The reason here I believe is the problem with identification of the control later in the page life cycle - this control would have to render under different parents, and with different IDs, etc. Looks like a very complicated and dangerous use case.
However there are several workarounds written here and there to clone controls on the page. For example checkout these threads: Copy/Clone Control, A Custom Copy Control - Copies Any ASP.NET Control.
All that beign said, in your case the easiest thing is just to create new list for each parent control. You do not need to copy any specific properties or data whatsoever, so no need for cloning overhead done in the solutions above.

ASP.Net MVC 3 Razor: how to create and pass info to a dynamic layout

In other languages (PHP/Python), I am used to creating a class which represents a given HTML page layout. These classes can have an unlimited number of attributes and dynamic features, such as Navigation (multi level), error messages, info messages, footer text, etc... Most of these items have defaults, but may be overridden on a per-page level. For example:
Layout = MainPage()
Layout.Title = "Google Image Search"
Layout.Nav1.Add("Google", "http://www.google.com", Selected=True)
Layout.Nav1.Add("Yahoo", "http://www.yahoo.com")
Layout.Nav1.Add("Bing", "http://www.bing.com")
Layout.Nav2.Add("Google Image Search", "http://......", Selected=True)
Layout.Nav2.Add("Google Shopping Search", "http://......")
Layout.Nav2.Add("Google Video Search", "http://......")
Layout.Nav2.Add("Google Web Search", "http://......")
or, handling errors:
try:
# do something
except ValidationError as e:
Layout.Error.Add(e)
or a php example:
$Layout->Info[] = "Your changes have been saved!";
My question is: how do I implement similar functionality into ASP.Net MVC 3 Razor (VB)?
So far, I have been able to see how you can use ViewData to pass various bits of data to a view. Also, I have been working with strongly typed views.
Frankly, I'm not sure who's job it is to have this logic, the controller or the view (or is there a model that should be in there somewhere).
Here is a summary of what I am shooting for:
A single place to initialize the default values for the layout (like the first layer of navigation, etc...)
Strongly typed attributes, such as Public Readonly Property Nav1 as List(of NavElement)
And a single place to render these layout elements (I assume _Layout.vbhtml)
Please forgive the here-and-there of this post... I'm trying to figure out the "right way" it's done on a platform that is both new (Razor) and new to me (ASP.Net MVC).
General advise very welcome!
I usually have a controller property (MainMenu) which I add to the ViewData dictionary in Controller.OnResultExecuting in my BaseController. Note that it's named ViewBag in mvc3 and it's a dynamic object.
Another approach would be to use sections in razor. Look at this question: ContentPlaceHolder in Razor?
I lean toward the fat models, skinny controllers perspective. If it were me I would create a base class for your page models that provides support for your common data. You can then inherit from that for individual page models and store your page specific data there.
The MVC implementations that have worked well for me usually have relatively clean Controllers. The controller is just the connector, getting the data from the request into the model and then handing off the prepared model to the correct view.
As for how you store collections of things in .Net - look at the classes that implement IEnumerable interface. Specifically focus on the Dictionary and the List classes. Dictionary objects store name/value pairs and can include nested dictionaries. You can work with them almost exactly like you can use multi-dimensional arrays in PHP. List objects are just indexed collections of items of the same type. You can work with them just like a simple array in PHP.
One side note - if you're just getting started in .Net and coming from a PHP/Python background, it might be better if you can switch to C#. You'll find the syntax much more comfortable and the tutorials/examples more plentiful (especially in the asp.net mvc world)
It's not difficult! :-)
If layout model is of the same type of the content page, the association is automatic! Here is the simplest example...
This is a test layout:
#model string
<style>
.test
{
background:#Model;
}
</style>
<div class="test">
Ciao
</div>
#RenderBody()
And this is a test content page
#{
Layout = "~/Views/Shared/_Test.cshtml";
}
#model string
...blah blah...
Just call the View with something like:
...
return View("Name", (object)"Green");
and it's done! The model is the same in the content page and in the layout page!
Andrea
P.S.: Believe me! This is useful!!! Maybe it's not the best for purists, but it's really useful!!! :-)

asp.net best practice string concatenation

I am trying to find the best practice for generating and outputting html which would require a database query first to obtain the info. Currently in the aspx page I have a div with runat server:
<div runat="server" id="leaflet"></div>
Now just as a start to do a bit of testing I have a method that runs on page_load that basically does:
private void BuildLeaflet(string qnid)
{
//gets leaflet details
QueryLeafletDetails();
//return concatenated content string
leaflet.InnerHtml "<h1>" + dr["LSC Descriptor"] + "</h1>";
}
In the real solution the return is a concatenation of about 10 fields some very long as they are content.
I don't by any means think this is the best solution, but what is? A StringBuilder? Can I Write Each Part in turn to the site avoiding the concatenation in the method? Is the server div even best?
Edit: Forgot to put some of my content sections have simple (limited) html in them already such as paragraph, list... This allows me to easily produce documents for web and printing, I just use different stylesheets.
I would use <asp:Literal runat="server" enableViewState="false" id="leaflet" />. This doesn't generate any tags on the page, and doesn't stuff all the text in the ViewState.
And yes, use StringBuilder if you need to concatenate many long strings. This will be way more memory efficient.
The other solution would be to see if you can make some fixed markup on the page and put the contents of each DB field in it's own control (<asp:Literal />?).
I'd use either string.Format, if the number of fields is fixed (and relatively small), or a StringBuilder, otherwise. Readability of the code would be my guide, less so performance. You might also want to think about abstracting this out into a UserControl if you plan to reuse it. Then you could give it settable properties and build the render logic into the control to avoid repeating yourself.
Various people have benchmarked this - iirc format is fine for <4 items, simple concats for <7, stringbuilding above that.
I strongly advise against creating HTML as strings btw.

Resources