This article provides an ASP.Net AJAX TooltipExtender. The
code and sample website can be downloaded here (TooltipWebsite.zip).
Due to the ASP.Net AjaxControlToolkit I have become very
fond of small and usable components which improve overall user experience. The ControlToolkit
contains - and lacks - several very usable components.
One component I would love to see would be a TooltipExtender
– allowing for both static and dynamic text, allows animations and can be
customized where it is required.
In an attempt to match this kind of functionality I made a TooltipExtender.
The only functionality lacking is animation.

Static
1: <tt:TooltipExtender
2: id="TooltipExtender1"
3: TargetControlID="lblStatic"
4: runat="server"
5: Delay="1"
6: Direction="Left"
7: TooltipWidth="300"
8: >
9: <TooltipTemplate>
10: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
11: Ut ut nunc. Mauris et sem et est semper cursus. Ut rutrum
12: dapibus nisl. Vestibulum sit amet lacus. Aliquam ut pede ut enim
13: pharetra scelerisque. Sed pharetra. Etiam eget elit vel nulla
14: iaculis porttitor. Sed nec quam. Sed semper gravida dolor. Nullam
15: dignissim pede ac nisl. Fusce viverra pharetra quam.
16: <ul>
17: <li><a href="http://www.microsoft.com">Microsoft</a></li>
18: <li><a href="http://www.apple.com">Apple</a></li>
19: </ul>
20: </TooltipTemplate>
21: </tt:TooltipExtender>
Dynamic
1: <tt:TooltipExtender
2: Direction="Bottom"
3: ServiceMethod="DynamicPopulateMethod"
4: CacheDynamicResults="false"
5: id="tt1"
6: Delay="100"
7: TargetControlID="lblDynamic"
8: runat="server" />
Properties
- TargetControlID: id of target control.
- Delay: How much ms before the item is shown (handy for webservice calls).
- Direction: Left, Right, Top or Bottom.
- TooltipWidth: Width of the tooltip.
- ServiceMethod: Pagemethod for servicecall (same as other pagemethods – like from the DynamicPopulateExtender).
- ServicePath: Path to webservice.
- CustomScript: Method of webservice.
- CacheDynamicResults: Should results be cached.
Cheers,
CJ.
A paginator is often used as a means to navigate through pages. These pages can contain anything you would want. Examples are a) paging through the results of a query or b) paging through a report and c) etc. This article provides the code and a description for a paginator control in ASP.Net and uses the example of paging through results to illustrate how to use this control.
Download the code here (paginator.zip)
I’m assuming everybody already knows what paging exactly is - but if you really don’t know you should look at http://www.google.com/ (thank you for the visitors!) A quick glance at Google reduces the methods to implement paging into the following two:
-
retrieve total number of items
-
retrieve the requested subset of items
As a bit of a side-track, the following code is how I usually retrieve and bind my data for paging:
1: private void BindFooList(int _PageIndex){ 2: int totalrecords = 0;
3: int pagesize = 10;
4: System.Collections.Generic.List<Foo> l = FooService.GetFooList(pagesize, _PageIndex, out totalrecords);
5: rptFooList.DataSource = l;
6: rptFooList.DataBind();
7: }
As you can see I use a pagesize and a pageindex parameter to specify how many results a page contains and which page I want to retrieve. The totalrecords (out) returns the total number of items found, which, of course, is, usually, different than the number of items actually returned. In the future I will add at least one article about how to limit the number of items returned by the function. The paginator control is specified as:
1: <cc1:Paginator
2: ID=”pagFooList”
3: PageSize=”10?
4: PageRadius=”4?
5: TotalRecords=”52?
6: AllowPageSizeChange=”false”
7: FinishButtonVisible=”true”
8: FirstButtonTitle=”first”
9: NextButtonTitle=”next”
10: PreviousButtonTitle=”previous”
11: LastButtonTitle=”last”
12: InfoResultsPerPage=”# of Foo per page”
13: ResultInfoFormatString=”{0} - {1} of {2}” 14: runat=”server” />
Properties
PageSize: How many results are shown on a page
PageRadius: The radius of the number of pages a user can click through
TotalRecords: Total number of items
AllowPageSizeChange: Allow the user to change the number of items displayed
FinishButtonVisible: After the last page allow for a finish button to close the paging
InfoResultsPerPage: The text of the label to change the number of items per page
ResultInfoFormatString: Formatstring of the information label 0) index of first item shown 1) index of last item shown 2) total number of results
Events
GoToPage: issued when a new page is requested through the paginator.
PageSizeChanged: issued when the page size is changed by the user.
Finish: issued when the user hits the finish button.
When only the control code is written in the .aspx file the paginator will already show up – and after a DataBind() the paginator will display the requested pages. The only thing left to do is to implement the actual paging in the codebehind. We still want to page through our results - right?
1: private void BindFooList(int _PageIndex)
2: { 3: int totalrecords = 0;
4: System.Collections.Generic.List<Foo> l = FooService.GetFooList(pagFooList.PageSize, _PageIndex, out totalrecords);
5: rptFooList.DataSource = l;
6: rptFooList.DataBind();
7: pagFooList.PageIndex = _PageIndex;
8: pagFooList.TotalRecords = totalrecords;
9: pagFooList.DataBind();
10: }
11:
12: protected override void OnInit(EventArgs e)
13: { 14: pagFooList.GoToPage += new PaginatorEventHandler(pagFooList_GoToPage);
15: pagFooList.PageSizeChanged += new EventHandler(pagFooList_PageSizeChanged);
16: base.OnInit(e);
17: }
18:
19: void pagFooList_PageSizeChanged(object sender, EventArgs e)
20: { 21: BindFooList(0);
22: }
23:
24: void pagFooList_GoToPage(object sender, PaginatorEventArgs e)
25: { 26: BindFooList(e.NewPage);
27: }
Download the whole website (paginator.zip) and please let me know if it was useful to you!
Cheers.
CJ.
This is an article about outputting data to the browser only
once, specifying where it should be outputted. The result
is a control that can write out a single script to the header of the
.aspx file (as an example). This control can be downloaded at outputonce.zip.
While programming for the web I often find the need to have some output
sent to the client only once. A simple example is to include a
javascript file – or function – when it is required. This output need
usually arises while developing (dynamic) usercontrols.
Problem setting
1. Imagine a couple of usercontrols using the prototype.js file. The
usercontrols are not always loaded and there is thus no need to include
this file always and everywhere (don’t include it in the masterpage).
2. Imagine a repeater with formfields and some dynamic calculations
using a javascripted function. When the repeater does not contain any
data – there is no need to include the javascript function.
Solution
As an attempt to fix these issues I created a small control named
OutputOnce. This control makes use of a property called OutputKey and
the Page.ClientScript.IsClientScriptBlockRegistered and
Page.ClientScript.RegisterClientScriptBlock functions to ensure that
the script will only be rendered once. Additionally the control
contains an OutputLocation property to specify if the data should be
rendered INLINE or in the HEAD.
The ASP.Net code will look like
1: <uc:OutputOnce
2: ID=”outputonce”
3: OutputKey=”prototype”
4: OutputLocation=”Head”
5: runat=”server”>
6: <script type=”text/javascript” src=”prototype.js”></script>
7: </uc:OutputOnce>
Please find the code for this control at the top of this page. Known issues:
1. It is not possible to send the AjaxScriptManager to the HEAD.
Good luck, and please let me know of any issues.
The information in this article is no longer valid. Please go to the new version found at http://weblogs.asp.net/cjdevos/archive/2008/06/19/ajax-extender-for-tinymce-continued.aspx. The current downloads are removed.
A while ago I was looking for a usable editor in one of the web applications I am working on. There are quite a few alternatives but I ended up picking TinyMCE.
TinyMCE is a very easy to use editor. Both for users and developers. It's great to write 1 small line of code to have textareas turned automatically into usable editors!
Using TinyMCE would be like:
1: <script type=”text/javascript” src=”/tinymce/jscripts/tiny_mce/tiny_mce.js”></script>
2: <script type=”text/javascript”>tinyMCE.init({mode : ‘textareas’, theme : ’simple’});</script>However – this control actually turned into a small nightmare when textareas lived INSIDE an UpdatePanel.
Some of the problems:
1. After an asynchronous postback the editor was gone.
2. Values were not submitted to the server.
When searching the web for these issues, you’d find several links which would help you out a bit. Some of the solutions where:
a. before the postback is made the following statement must be issued: tinyMCE.saveTrigger(false, true);
b. issue an mceAddControl after the postback is finished.
c. Issue an mceRemoveControl before the postback starts.
d. Reset the idCounter to 0.
Only part d. was absolutely incorrect. It can lead to strange behaviors with textareas both inside and outside an updatepanel.
For my solution I took part of the input given by steho706 (http://forums.asp.net/members/steho706.aspx) in the discussion at http://forums.asp.net/p/1131150/2154829.aspx. He actually nailed the problem by mentioning the mceRemoveControl statement with the right event.
For me, however, the solution had one drawback. Textareas which were not inside an UpdatePanel refreshed as well…
And to nail this particular issue I decided to write an AJAX Control Extension, which you can find attached to this article.
The control will be usable by writing the following code:
1: <asp:TextBox ID=”TextBox1″ runat=”server” Width=”100%” Height=”200″ TextMode=”MultiLine” />
2: <cc:TinyMCETextBoxExtender TargetControlID=”txtTextBox1” ID=”TinyMCETextBoxExtender1″ runat=”server” />
For completeness sake here are excerpts of the code as well:
From the Behavior
1: this.registerPartialUpdateEvents();
2: this._pageLoadingHandler = Function.createDelegate(this, this._pageLoading);
3: this._pageRequestManager.add_pageLoading(this._pageLoadingHandler);
4:
5: var element = this.get_element();
6: if (tinyMCE.getInstanceById(element.id) == null || tinyMCE.getInstanceById(element.id) == “undefined”)
7: tinyMCE.execCommand(‘mceAddControl’,false,element.id);
8:
9:
10:
11: ...
12:
13: _pageLoading : function(sender, args) { 14: if (this._postBackPending) { 15: this._postBackPending = false;
16:
17: var element = this.get_element();
18: var panels = args.get_panelsUpdating();
19: for (var i = 0; i < panels.length; i++) { 20: var el=element;
21: while(el!=null)
22: { 23: if(el==panels[i]) break;
24: el = el.parentNode;
25: }
26: if(el!=null)
27: { 28: if (tinyMCE.getInstanceById(element.id) != null && tinyMCE.getInstanceById(element.id) != “undefined”)
29: { 30: tinyMCE.execCommand(‘mceFocus’, false, element.id);
31: tinyMCE.execCommand(‘mceRemoveControl’,false,element.id);
32: }
33: break;
34: }
35: }
36: }
37:
From the Extender
1: [Designer(typeof(TinyMCETextBoxDesigner))]
2: [ClientScriptResource(“TinyMCETextBox.TinyMCETextBoxBehavior”, “TinyMCETextBox.TinyMCETextBoxBehavior.js”)]
3: [TargetControlType(typeof(TextBox))]
4: public class TinyMCETextBoxExtender : ExtenderControlBase
5: { 6: protected override void OnLoad(EventArgs e)
7: { 8: // ** load scripts
9: if (Page.Items[“tinymce”] == null)
10: { 11: HtmlGenericControl Include = new HtmlGenericControl(“script”);
12: Include.Attributes.Add(“type”, “text/javascript”);
13: Include.Attributes.Add(“src”, Page.ResolveUrl(“~/tinymce/jscripts/tiny_mce/tiny_mce.js”));
14: this.Page.Header.Controls.Add(Include);
15:
16: //Config MCE
17: HtmlGenericControl Include2 = new HtmlGenericControl(“script”);
18: Include2.Attributes.Add(“type”, “text/javascript”);
19: Include2.InnerHtml = “tinyMCE.init({mode : ’specific_textareas’, theme : ’simple’});”; 20: this.Page.Header.Controls.Add(Include2);
21:
22: Page.Items[“tinymce”] = true;
23:
24: if (!Page.ClientScript.IsOnSubmitStatementRegistered(this.GetType(), “tinymcetriggersave”))
25: { 26: Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), “tinymcetriggersave”, “tinyMCE.triggerSave(false,true);”);
27: }
28: }
29: base.OnLoad(e);
30: }
31: }