In this post I want to demonstrate a great usage of extension methods in C# 3.0.
Most of you are probably aware of the fact that it is not allowed to access a Controls from a thread other than the one in which it was created. The typical solution involves checking the Control’s InvokeRequired property, and in case it’s value is true, calling Invoke (or BeginInvoke), which marshals the call to the Control’s thread.
For example, in case we have a button, which we want to enable or disable from another thread, we’ll typically write the following method:
1: private void SetButtonEnabled(bool enabled)
2: {
3: if (this.InvokeRequired)
4: {
5: MethodInvoker method = () => SetButtonEnabled(enabled);
6: this.Invoke(method);
7: }
8: else
9: {
10: this.btnRunProcess.Enabled = enabled;
11: }
12:
13: }
Note that the method invokes itself in case invoking required.
However, in most situations, we’ll want to update numerous controls from another thread: change progress bar, enable/disable controls, etc… Using the above technique, each operation requires a separate function.
So how about generalizing things, making use of the newest C# 3.0 enhancements? The idea is to create an extension method, that takes a delegate as an argument. Using lambda expressions permits a very nice syntax. Here is the extension method:
1: public static class ControlExtensions
2: {
3: public static void Invoke(this Control control, Action action)
4: {
5: if (control.InvokeRequired)
6: {
7: MethodInvoker method = () => Invoke(control, action);
8: control.BeginInvoke(method);
9: }
10: else
11: {
12: action();
13: }
14: }
15: }
Note that I’ve used the BeginInvoke method to prevent the waiting for the completion. Feel free to change it to Invoke.
And this is a typical usage for this method:
this.Invoke(() => this.progressBar1.Value = 0);
this.Invoke(() => this.progressBar1.Visible = true);
this.Invoke(() => this.btnRunProcess.Enabled = false);
I don’t think it is an extremely new idea, and I guess some of you are already using some similar technique. However, my goal in this post was to show you a great usage of extension methods. While I predict this C#3.0 enhancement to be the most over-abused one, there are many great usages that can make our life much simpler.
This is a sample application that shows a usage of the above method for a long running process that runs using BackgroundWorker:
Have fun.
Shlomo has shared with us in his post a trick that can be used to pass parameters to event handlers. The trick is based on the fact that every HTML element can have unlimited custom attributes, therefore, using element's setAttribute() method it is possible to append any attribute you can imagine. Shlomo also shows us one of the possible ways of dynamically creating rows in HTML table using browser’s DOM, and attaching events to elements .
One drawback with this trick is that is breaks HTML 4 compatibility of the web page. While in most cases this is not an issue, in general we should always prefer not to break compatibility if possible.
Following that, I’d like to demonstrate another way of achieving the same result without breaking compatibility, using jQuery library. The library provides a fast, clean and cross-browser development experience.
We will start with creating a basic HTML markup for our page. The following already includes a reference to jQuery library, and a definition for a CSS class we’ll use for generated table cells. I’m using the recently released jQuery version 1.3.2 with Visual Studio annotations, which provide a nice intellisense experience inside VS 2008. For production deployment, the reference should be changed to a minified version of jQuery. For more information about jQuery intellisense support in VS 2008, please read ScottGu’s blog post.
1: <html xmlns="http://www.w3.org/1999/xhtml">
2: <head>
3: <title>Dynamic HTML Table Creation with jQuery</title>
4:
5: <script src="jquery-1.3.2-vsdoc.js" type="text/javascript">
6: </script>
7:
8: <style type="text/css">
9: td.tableCell
10: {
11: padding: 5px;
12: }
13: </style>
14: </head>
15: <body>
16: <table id="tbl" border="1">
17: <tbody>
18: </tbody>
19: </table>
20: </body>
21: </html>
The second step is to write a function that dynamically generates rows for HTML table:
1: <script type="text/javascript">
2: function createDynamicTable(tbody, rows, cols) {
3: if (tbody == null || tbody.length < 1) return;
4: for (var r = 1; r <= rows; r++) {
5: var trow = $("<tr>");
6: for (var c = 1; c <= cols; c++) {
7: var cellText = "Cell " + r + "." + c
8: $("<td>")
9: .addClass("tableCell")
10: .text(cellText)
11: .data("col", c)
12: .appendTo(trow);
13: }
14: trow.appendTo(tbody);
15: }
16: }
17: </script>
The createDynamicTable() function accepts three arguments: the jQuery object representing the table and desired number of rows and columns in the table. On line 3 the function performs input validation for the table reference argument. In general, jQuery selection returns an array of elements, so if nothing was selected, the length property will contain a zero value.
The function then loops through rows and columns generating table rows and table cells. Line 5 demonstrates the simples way to create any HTML element, and in particular, a table row. Lines 8 through 12 are actually one splitted line. One of the most recognized qualities of jQuery is functions chainability, or the fluent interface it provides, so every function actually returns a modified jQuery object that can be further modified by the next chained function call. So line 8 creates a new table cell, line 9 appends a CSS class to that cell (the class was defined in a header of the HTML), line 10 sets the inner text of the cell.Line 11 sets a column number into element’s data (I’ll elaborate on that in a moment), and line 12 appends the current element (table cell) to the table row created above. Finally, line 14 appends the table row to the table itself – jQuery will append the row to the <tbody> element of the table.
Now, as for the data function. jQuery can store any data we want for any element on our page. Think of it as an array of properties (a hash table to be more precise), attached to an element. Internally, jQuery manages cache object, which is a hash table itself, where it can save any data it wants for any element. It is possible to achieve the very same by declaring a new array, and setting a unique ID for every element on our page, but why bother? jQuery makes our life easy.
The next step is to call that function. I want the table to be generated as soon as possible. The $(document).ready() event is the most appropriate candidate for that purpose:
1: $(document).ready(function() {
2: createDynamicTable($("#tbl"), 10, 5);
3: });
In the script above, I’ve attached an anonymous function to the ready event of the current document. The ready event is fired as soon as the DOM is ready for manipulations, before loading images and other external resources. I’m calling the createDynamicTable function passing the table with id=”tbl” – the is what the $(“#tbl”) selector does. The function supposed to create 10 rows with 5 cells in each. Something like that:
Now, the last step for this sample is to react to the click event of each cell alerting with the column number. It can be achieved by adding a single line of script (well, a splitted one) into the $(document).ready handler. This is the modified handler:
1: $(document).ready(function() {
2: createDynamicTable($("#tbl"), 10, 5);
3: $("#tbl td.tableCell")
4: .click(function() {
5: alert("Clicked Col=" + $(this).data("col"));
6: });
7: });
On line 3 I’m selecting every table cell element which is a child of an element with id=”tbl”, and includes a CSS class “tableCell”. For this sample, the same effect could be achieved by selecting all the table cells: $(“td”), or by selecting all the elements with class “tableCell”: $(“.tableCell”). All of the selectors above will result the same collection of elements – the table cell we’ve created before.
Following the selection, on line 4, an anonymous function is attached to the "click” event of every selected element (every table cell). jQuery’s event handler functions run in the context of the attached DOM element, therefore, the this variable inside the function holds a reference to a DOM element representing our cell. To get the data stored for the element, the element must first be selected and converted into jQuery object. This is achieved by the $(this) construct following the call to a data(“col”) function that will return the column number for the clicked cell (we have stored it in the createDynamicTable) function.
That’s all, folks. Now every cell click will result an alert:
Pretty straight-forward in my opinion. Write me if you have questions and/or suggestions.
UPDATE: You can download the source code for this from my SkyDrive:
There are times you need to develop a data-entry web form calling and AJAX-enabled web service to perform some complex computations that must be done on the server (for example, when a database access needed to do the computation). The computation is sometimes based on numerous data-entry fields, so when a change in one of the fields has occurred, you want to send a web service request to re-compute the data.
As a most simple example, I’ll create a form that is capable of doing an extremely difficult task of adding two integer numbers. Here is how it looks like:
And here is the underlying sophisticated HTML fragment:
<input type="text" size="4" id="numA" onchange="add()" />
+<input type="text" size="4" id="numB" onchange="add()" />
=<input type="text" size="4" id="result" readonly="readonly" />
The add() function calls the web service, which in turn adds the two numbers and returns the result. Here is the add() function:
1: function add() {
2: var a = Number($get("numA").value);
3: var b = Number($get("numB").value);
4:
5: if (!isNaN(a) && !isNaN(b)) {
6: CancelScriptService.CalcService
7: .Add(a, b, function(res)
8: { $get("result").value = res; });
9: }
10: else {
11: $get("result").value = "";
12: }
13: }
The function converts the text values it’s got from the input boxes, validates the values for being numbers (this is not a full validation, but it will do for now), and then calls the Add() web method using the proxy generated by the ScriptManger. The third argument of the web method call function is a delegate to a function that will be called upon success. To shorten the code, I’ve created a JavaScript anonymous delegate (sort of) that updates the result.
I’m omitting the ScriptManager definition, and the ServiceReference declaration. The full source of the sample is attached to this post.
And here is the ingenious web method:
[ScriptMethod]
public int Add(int a, int b)
{
return a + b;
}
Every time one the two input boxes changes, a web service call will be administered and the result will be put into the third text box. But what happens when the network is slow, or the calculation takes a couple of seconds to proceed? For the sake of the demo, I’ll suspend the current thread in the web service method for 5 seconds:
[ScriptMethod]
public int Add(int a, int b)
{
Thread.Sleep(5000);
return a + b;
}
The thing is, the MS AJAX library can handle only one async call at a time, so it queues all the subsequent calls for later execution. In our case, if we change input boxes values numerous times, we’ll see the result box updated with a new result every 5 seconds. Pretty odd, isn’t it?
To solve the problem, we somehow need to abort the active web service call when the user inputs a new value. For that purpose, the MS AJAX library includes a WebRequestExecutor object that is a member of the WebRequest object created upon every call to a web service. However, when we call CalcService.Add() proxy function, we’re actually calling a singleton instance method, which for some reason, does not return anything. Therefore, to solve it, we need to instantiate an actual CalcService object and call its Add() method. Here is a revised code:
1: var lastExecutor = null;
2:
3: function add() {
4: var a = Number($get("numA").value);
5: var b = Number($get("numB").value);
6:
7: if (lastExecutor != null && lastExecutor.get_started()) {
8: lastExecutor.abort();
9: }
10: if (!isNaN(a) && !isNaN(b)) {
11: var calcService = new CancelScriptService.CalcService();
12: var request = calcService.Add(a, b,
13: updateResult, onFailure);
14: lastExecutor = request.get_executor();
15: }
16: else {
17: $get("result").value = "";
18: }
19: }
20:
21: function updateResult(res) {
22: $get("result").value = res;
23: }
24:
25: function onFailure(ex) {
26: if (!lastExecutor == null && lastExecutor.get_aborted()) {
27: // the execution was aborted
28: return;
29: }
30: // handle the error here
31: }
The revised add() function starts with a regular number conversion and validation. Disregard lines 7-9 for one moment. On line 11, I create an instance of CalcService proxy class, and call its Add() method to initialize a web method call. Now, however, the method returns a Sys.Net.WebRequest class instance, which includes and Sys.Net.WebRequestExecutor object for the current call. I’m keeping the last instantiated Executor in a member variable, to be able to use it on the next function call.
The executor is capable of aborting the current request, and this is what I’m doing on lines 7-9. Upon changing one of the values in the input boxes, the function checks whether another web request is active, and if there is, it aborts the request, and instantiates a new one.
An important point to notice here is that when the current WebRequest is aborted, the AJAX library raises an exception, therefore, we have to handle is gracefully. That is what I’m doing on lines 26-28.
This time, the user of the application can change the input boxes’ values numerous times – the result will be updated only once – 5 seconds from the last change. Try it yourself, the source code is here:
Have fun.