I think the question may seem a little weird, but here's the details.
The Goal : To retrieve a set of pairs (text, value) for various reasons. one example for that of them is retrieving the alphabet, each letter will be used as an anchor or a LinkButton, the text value will be the letter and the click event will take the value part of the pair and place it in a stringFormat() to form a "Parametrized URL"
I've used two approaches for this goal but I don't know which is better!
1. Using a Repeater
A repeater that will have a LinkButton in it's ItemTemplate and through this blocks and will set the text to the 'text' and using eval and the 'value' to create the QueryString.
2. Using StringBuilder
Create an instance of StringBuilder
Use a loop with a counter equal to the total pairs to be retrieved. and append a certain string format that will build a long string with all the needed anchors for navigation using some code like this
Links_strngBuilder.Append(string.Format("<a href='/data.aspx?page={0}'>{0}</a>", chrctr))
and finally convert the String Builder instance to a string and assign it to a label
Note: the chrctr text and value fields will be retrieved as you suggest [in each loop from the database] or [loaded in an array/arrayList/List<> to store the values and save all those connections to the db]
Where i work we will never use a stringbuild becouse of the designer. We dont want the designer in the codebehind if he has to make a simple change. so keep the markup in the view and codebehind in the codebehind.
Edit
Other advantage of repeater is the change of cycle is much easier. No need to recompile and perhaps redeploy the tweak the UI, just edit the ASPX template, save and refresh.
I don't know anything about how these two approaches perform (in terms of memory usage and speed) comparing to each other but I'd definitely go for Repeater because:
The code is much easier to understand & support
Using a StringBuilder reminds me the days of the classic ASP when the Response.Write was used widely.
You can't use any of the benefits of the Visual Designer with a StringBuilder.
-- Pavel
I think building the output fits more in client side(e.g. when you do an ajax call and want to show the results in html) than server side except when your build a custom server control.
In addition, if you use the repeater you have the extensibility option whenever requirements changed, and you have more control and facilities(like event handling and styling with css and so forth).
Related
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/
How can I get my CheckBoxList to have three possible states ? More precisely, is there a way to have three possible states for each checkbox : checked, unchecked, undefined (in most GUIs this is represented as a full square).
Alternatively, do you recommend another control that would meet these needs ?
UPDATE : Ok, given that HTML does not support tri-state checkboxes, I'm looking for a way to 'CSS' (color fill, highlight, etc...) the checkboxes of the items that are in that 'undefined' state from my server point of view.
Not all GUIs represent undefined as a full square. That's why it's going to be clearer to use one of the following:
1. Radio boxes
2. Dropdown
3. ListBox
Any asp.net control you use will ultimately need to be rendered as an html checkbox, which can only be checked or unchecked. You could use a data- attribute to keep track of extra state behind the scenes, but that wouldn't be reflected in the UI.
I suppose you could also implement a client-side solution using JavaScript and CSS as well.
You could just extend or derive from the CheckBoxList and create your own custom control from it.
Here is an example of this.
Custom CheckBoxList
I have decided to use CheckBoxList anyway, since I need two states accessible by the user, and a third one not accessible by the user but to display inconsistencies.
The way I have solved this is through Javascript + CSS. Some bits of ideas here: http://css-tricks.com/indeterminate-checkboxes/
I have a section on my website where I plan to add a lot of text-based content, and rather than display this all at once it would be nice if I could add paging on just these pages. If possible, I would like to put all of my content within one content item and have the paging work automatically, building a URL along the lines of http://example.org/articles/title?page=2 or similar.
I've stumbled across an article that mentions paging with Sitecore items and this seems rather close to what I require, although mine requires pagination on a single content item, rather than multiple items. Can someone help me adapt this article towards my needs (if it's on the right track of where I should be looking)?
Is it possible to do this with a Sitecore content item?
http://briancaos.wordpress.com/2010/09/10/create-a-google-style-paging-component-in-c/
I think you'd either want to create your own WebControl and define a custom Render() method that reads the query string to write out the correct information, or you could even do it all in a Sublayout (a user control ASCX file). I've done this before by adding in a custom tag in the Rich text editor via Sitecore (I think I used <hr class="page-break" />) then in my ASCX I'd look for that HTML tag and split the content into chunks from that. I think my solution also used jQuery for some of it but you could probably do it with C# too.
Edit:
You'd want to split the tasks up and have the "paged" content as well as a list of pages (like the article you referenced) so you can easily generate the page buttons. Both of these could be done in two separate repeaters.
You can split the text from a single field into the different pages using approach described here: Split html string to page. All you need to do after that - read the query string and display appropriate block.
If I understand you correctly you have an Item in Sitecore that has x number of text fields and you only want a subset of those displayed depending on input in the querystring ?
In it's simplest form you want a sublayout that handles that.
Basically I'd imagine you having fields called Text1, Text2, text3 etc.
This .ascx could then retrieve the data for fields the fields you'd want using the control and adding them.
Then you could use the code from the article to generate the paging links.
This should be simple enough, but I'd say it would be a better idea to have an item in sitecore and use it's children as the data you want viewed and paged.
It's nicer because if you start out with 5 "page" fields and suddenly want 10, your item will keep on growing, where children can be added without bloating the parent page. Plus the user could then order the children how he sees fit.
I hope this helps a bit.
I have about 20 div's in an aspx page. At any time, only one of them will be visible. I need to decide which div to show depending on the Query String.
http://...?mode=<ModeName>
The easy way would be to start with all div's invisible, then just put the QueryString in switch and write out cases for all the possible ModeNames (or get it in a big if-else structure)
I dont really like hard coding things because if in future if I add/remove any div then I need to "remember" to do the necessary changes in the places that toggle divs.
I was thinking of creating an enum with all names and passing that enum to the function so I can iterate through all enums and set visibility accordingly. This way I only need to add the div name in the top enum declaration. But it did not quite work out that way (probably I'm too fiddly to get it to work)
Is Switch block my only way out of this? Does anyone have a better way to do this?
Thanks in advance!
I would do some or all of the following:
Define the various modes of your window in an enumeration (public enum ModeNames {View, Edit, Create, Summary ...}). Make this enumeration generic but descriptive.
Expose a property DisplayMode that parses the QueryString into the enum value. You should have control of the ModeNames added to the QueryString, but since it is the query string and thus the client can type in whatever they like, I'd put in some error-checking that will show a "default" view mode if the QueryString is not one of the expected values.
Give the divs a runat=server and an ID attribute (I'm guessing you already have since you want to do this in C# and not JavaScript), and in your Page_PreRender handler, set the Visible property of each div (referenced by its ID as an object) to an expression evaluating whether the current DisplayMode is one of the modes in which this div should be visible (e.g. thisDiv.Visible = new[]{ModeNames.Create, ModeNames.Edit}.Contains(DisplayMode)).
Alternately, instead of the second step, you can do this in the markup, either by specifying the Visible property of the div (as a server-side object) using a similar inline expression evaluating DisplayMode, or by including an OnLoad JavaScript handler for the div (which no longer has to be server-side) that sets the visibility using the DOM, based on the same inline C# expression.
I suggest to set a relation between the data passed at querystring and the names(and ids) of the divs you want to handle.
The rest you should know, use an scriptmanager to execute Javascript code to hide/show proper divs depending of what you read from querystring,
Hope that helps,
I thought I would ask this question to see why many examples and people prefer to use inline databinding in the aspx code vs implementing an OnDataBinding event when using WebForms.
For any databound control (eg. Repeater, GridView, etc) I always implement the OnDataBinding method for field level controls if I need to do anything that isn't built in out of the box (eg. I need to do an Eval). Most examples I see have the code right in the aspx page using the inline <%# syntax.
Example of inline ASP.NET code:
<asp:Literal ID="litExample" runat="server"
Text='<%# Eval("ExampleField").ToString() %>' />
Example of how I prefer to do it:
In the aspx:
<asp:Literal ID="litExample" runat="server"
OnDataBinding="litExample_DataBinding" />
In the codebehind .cs:
protected void litExample_DataBinding(object sender, System.EventArgs e)
{
Literal lit = (Literal)(sender);
lit.Text = string.Format("{1} - {2}",
Eval("ExampleField").ToString(),
Eval("ExampleField2").ToString());
}
I personally prefer the codebehind method because it keeps my aspx pages clean and I don't have all this inline code all over the place and the next guy just knows to always look in the .cs files for code changes. The seperation of presentation and code is also maintained better this way as the HTML is place holders only and the codebind is determining what is actually being put in control.
Now these are very basic examples. The field could be a integer that you want to format with leading 0s or a DateTime that needs a specific format etc. It could also take all sort of manipulation and code to get the finally value that should be stored in the 'Text' property at the end.
Where do you draw the line and move it to the codebehind if you are using inline code?
What are the pros and cons for doing it either way?
Does one take more overhead than the other?
Edit Note: I am not talking about assigning a value to a control that is just on the page but one that is being databound to because it exists in a repeater template or gridview item template etc... Obviously a literal sitting on a page you can just assign in code.
Edit Note: I thought I would gather more response, especially with regards to the overhead. Do most people NOT use the OnDataBinding events?
I much prefer the opposite. I prefer to keep my code-behind limited to procedural code, and keep all my declarative code in my Aspx page. In your example above, the literal is absolutely declarative and therefore (by my preference) would not belong in code-behind. Much more robust functionality generally goes in my code-behind, and I don't want my developers to be cluttered by having to sift through a bunch of initialization lines when trying to understand it.
There's little performance difference between them. A data binding expression is parsed and compiles out to something like
control.DataBinding += new EventHandler(ControlDataBinding);
and also
private void ControlDataBinding(object sender, EventArgs e) {
control.Text = Eval("Field");
}
In this case, the OnDataBinding method is not overridden. The base Control.OnDataBinding method is executed, which raises the DataBinding event, causing the above code to execute.
When you override OnDataBinding, you're simply taking over before the base code is run, and get to set the Text property yourself (for example).
I dislike giving out partial answers, but I'll do it this time because I think it's neat, and it saved me recently:
I said that the data binding expression are parsed. In fact, all of the markup is parsed, code in C#, VB.NET or whatever language is generated, and this is them compiled into a class. When the page is requested, an instance of this class is created, and it begins its life.
You can locate these generated code files on disk sorry, I don't remember where. The interesting thing about them is that they still work, as code.
For instance, I recently had some fairly complex Infragistics grids set up, had all the formatting complete, and then found that I needed to be able to set the formatting at rumtime (to get the correct format into exported Excel files). In order to do this, I opened the source file (all grids were in a single user control) and was able to extract the configuration of each grid into a separate group of methods.
I was able to clean them up with ReSharper, extract common code sequences into a base class, and was left with one static method to set up each grid. I was then able to call them both for the initial setup, and for the setup of the dummy grid used for Excel export.
I prefer it your way with OnDataBinding. You can keep your codebehind clean by using a "Databind" region for all the OnDataBinding calls, and you can keep your markup clean by getting those horrible server-side code blocks out of there.
I think most people do it the inline way because it's easier to understand and to implement.
Actually I prefer to use the aspx for controls that you would expect to Bind, like listview, gridview, repeater and other similar controls.
For the other controls, I would set them in the codebehind, but directly (as part of the process I am doing, instead of calling the literal.DataBind or DataBind for the whole page). If it is an user/custom control, that I expect the callers to do a DataBind, then I would override DataBind and set the values.
That said, I usually has plenty of code outside the codebehind, and have a call to something like ShowUser, where I put those assignments to controls (instead of setting a property, then doing a bind, and having all those evals for simple controls).
I agree with caltrop. I like my markup to be clean and all my aspx/ascx code to reside in my code-behind files (where it belongs).
I only have one thing to add. I prefer not to litter my code with OnDataBinding() events wired for each of my databound controls. Instead I do it all in the OnDataBinding() event of the User Control that is being embedded in the bindable-control (such as the repeater in your sample).
For example, in my User Control's code-behind you would find:
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
litExample.Text = Eval("ExampleField") + " - " + Eval("ExampleField2");
}
From here you can set the properties of all your controls or call other methods to set them. Notice how, in my example, I didn't need to perform the boxing like you did here: Literal lit = (Literal)(sender);
That alone should save you on some performance (nanoseconds of course, but something worth measure). Read the section "Performance" here: http://msdn.microsoft.com/en-us/library/yz2be5wk%28v=vs.80%29.aspx
I am also at war with using strings in my code. I would have either used const string variables to define "ExampleField" and "ExampleField2" or set them up as public properties in the User Control that could then be set by the containing control/page based on the column name of the data object it will be bound against. This affords more flexibility and re-use of the control.
FYI: You don not need to call ToString() on Eval, as this method already returns a string.