and has 0 comments
Dearly Devoted Dexter is much darker than the first Dexter book. Maybe it is just because all the facts about Dexter are clear and it starts with a gruesome murder, insane special forces style. The title comes from the fact that he helps his sister, now partially in the loop about his Dark Passenger, to solve the newest serial killer case. Of course, Deb, now a seargent after Laguerta has died, has a personal stake in this, since one of the people the murderer abducted and intends to do bad things to, is her boyfriend, with whom she is very much in love.

It is interesting to develop the Dexter character in this way, especially since he is described as totally indifferent to the horrible fate of people he doesn't care about, yet he is still compelled to help his sister out.

I was a bit disapointed by the police work involved. If I were to believe Lindsay, the Miami police are a bunch of morons, following (badly) a set of procedures without any real talent other than badmouthing.

Elements from this second book in the Dexter series were clearly used in the series, but it is already a completely different story. The FBI agent that Deborah briefly dates in the series was inspired by the character of Kyle, shady government agent that she falls in love with in this book. The stalking of Dexter by the grumpy seargent Doakes is also mirrored from this book, although the motives and the outcome are completely different.

Again, the series evolves the Dexter character more and the story is more complex than the book, but by now it is obvious the TV show and the book are going in completely different directions.

All in all, a bit better than the first, darker, but also funnier. I have never laughed as much reading a book for a long time. Can't wait for the third book now.

and has 0 comments
Well, it may have been obvious for many, but I had no idea. Whenever I was writing a piece of code that uses a StringBuilder I was terribly upset by the lack of a substring method.

It was there all along, only it is the ToString method. You give it the startIndex and length and you're set.

Looking at the source, I see that in .Net 1.1 this method is only a normal Substring on the internal string used by the string builder. In Net 2.0, the method uses a InternalSubStringWithChecks internal method of the string class, which is using a InternalSubString unsafe method that seems to be more basic and thus faster.

and has 1 comment
I have been watching this TV Series called Dexter and slowly but surely I fell in love with it. It features a psychopathic serial killer that has a hobby of killing other killers. The story is long and I suggest you watch it to get it fully. Anyway, the series has reached season 3 and stars Michael C. Hall, which you may recognize from the Six Feet Under TV series. I've also noticed that the series is based on a book! So, naturally, I got the book and started reading it. It's Michael C. Hall on the cover there.

Darkly Dreaming Dexter is the first in a series of Dexter books by Jeff Lindsay. While it starts pretty much the same as the series, the series quickly moves away from the script in the book. However, the spirit is there, even if, of course, they had to make the lead character a little more likable in the series and the whole thing less bloody.

Imagine an emotionless killer, raised by his cop father to kill according to a code and also to be thorough and attentive to the details so that the police wouldn't catch him. He is also working for the Miami police department as a blood spatter analyst. The inner dialogues are really delicious, the way he sees the world as a cynical dark Data is both funny and deep. Lindsay manages to portray an alien being, silently watching the world we take for granted, hunting on the edge of our own morality.

And while I do enjoy the book, I have to say that the series is more complex and the story a bit more realistic. So, there, finally a movie or series that surpasses the book!

Actually, I think this applies to any dynamic modification of drop down list options. Read on!

I have used a CascadingDropDown extender from the AjaxControlToolkit to select regions and provinces based on a web service. It was supposed to be painless and quick. And it was. Until another dev showed me a page giving the horribly obtuse 'Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.'. As you can see, this little error message basically says there is a problem with a control, but doesn't care to disclose which. There are no events or overridable methods to enable some sort of debug.

Luckily, Visual Studio 2008 has source debug inside the .Net framework itself. Thus I could see that the error is caused by the drop down lists I mentioned above. Google told me that somewhere in the documentation of the CascadingDropDown extender there is a mention on setting enableEventValidation to false. I couldn't find the reference, but of course, I didn't look too hard, because that is simply stupid. Why disable event validation for the entire page because of a control? It seems reasonable that Microsoft left it enabled for a reason. (Not that I accuse them of being reasonable, mind you).

Analysing further, I realised that the error kind of made sense. You see, the dropdownlists were not binded with data that came from a postback. How can one POST a value from a select html element if the select did not have it as an option? It must be a hack. Well, of course it was a hack, since the cascade extender filled the dropdown list with values.

I have tried to find a way to override something, make only those two dropdownlists not have event validation enabled. Couldn't find any way to do that. Instead, I've decided to register all possible values with Page.ClientScript.RegisterForEventValidation. And it worked. What I don't understand is why did this error occur only now, and not in the first two pages I have built and tested. That is still to be determined.

Here is the code

foreach (var region in regions)
Page.ClientScript.RegisterForEventValidation(
new PostBackOptions(ddlRegions,region)
);


It should be used in a Render override, since the RegisterForEventValidation method only allows its use in the Render stage of the page cycle.

And that is it. Is it ugly to load all possible values in order to validate the input? Yes. But how else could you validate the input? A little more work and a hidden bug that appears when you least expect it, but now even the input from those drop downs is more secure.

Update:
My control was used in two pages with EnableEventValidation="false" and that's why it didn't throw any error. Anyway, I don't recommend setting it to false. Use the code above. BUT, if you don't know where the code goes or you don't understand what it does, better use this solution and save us both a lot of grief.

We are working on these projects in which people either receive an email with an invitation or they register on a web site or they simply play and expect an instant result. What is the best way to compute the chance of winning?

Case 1: People register then, at a certain date, an extraction of prizes takes place. Ah, this is the best and simple situation. You have the list of players, the list of prizes. Just do an index = Random(0,number_of_players) and if index is smaller than number_of_prizes, you know the person won a prize. A second random on the number of prizes will determine the prize itself. The win probability is number_of_prizes/number_of_players.

Case 2: People enter a site that allows them to play instantly and win a prize. Here the problem is trickier. While the algorithm is basically the same, prizes over people, you don't have the total number of players. There are some subcases here based on the following parameters:
  • The win campaign lasts for a certain amount of time or is indefinite
  • The prizes must all be given at the end of the campaign or not
  • The players play after they have received an invitation (email, sms, etc) or just randomly coming from ad clicks or for some information on the site
.

Let's assume that the campaign doesn't last for a finite time. The only solution is to pick a win probability and be done with it until you remain out of prizes. You always compute this by considering the number of people playing over a period of time, in other words the speed of people playing. However, in this case the only thing influencing the selected probability is a psychological one: how many people would need to win in order to have a marketing effect?

Now, if the campaign does have a finite time, you would use the speed of the people playing to determine the total number of people that would play. Let's assume you know people are visiting your site at an average rate of 1000 per hour, then you see how many are playing and you remember this percentage, so you can estimate the number of players per hour, then you just multiply that number to the total number of hours in the campaign. Again, we get to the prizes over people formula.

However, it is very important to know how people are deciding the participate in the extraction!

If it is just a game added to one's site, then the people are coming and going based on that site's popularity and hourly/daily distribution (since the number of visitors fluctuates). So just computing this from the first hour of people coming to the site and playing doesn't help, but it might when using the first day and maybe the first week. One week of statistical data is best to estimate the number of people over time. Then the formula is number_of_prizes_available_per_week/people_visiting_per_week. Where the number of prizes available per week is either the total number of prizes over the finite campaign time or an arbitrary number chosen by the campaign creator.

If, instead, people are being invited to play, as following an email promotion campaign, let's say, then they will come as soon as they read their email. That means they will flock to your site in the first hours, then just trickle in the next week, then nothing. That means that estimating the total number of players from the first hour or day is not really feasible unless you are certain of a statistical distribution of people playing games after email campaigns. It is difficult as different messages and designs and game types might attract more or less people.

A mixed hybrid can also exist, with a game on a site that also people are invited to play over email. Then all the parameters from above must be used. In any case, the best estimation I can think of comes from the total of players in similar campaigns. The more similar the better.

But what if ALL the prizes must be given to people, as required by law or simple common sense (so as not to be seen as keeping some for you or your friends)? Then one can adjust the probability rate to suit the extraction speed. The same prizes over people formula is used, but only on the remaning values. The probability of winning is given by number_of_remaining_prizes/number_of_remaining_people.

But that has some disadvantages. If the number of total participating people is badly estimated it will result into a roller coaster of probabilities. People playing in the first part of the campaign would be either advantaged or disadvantaged than the people in the last part as the total number of players is being adjusted over time to compensate for the first bad estimation.

Let's do a small example:








Day 1Day 2Day 3Day 4Day 5Day 6Day 7
People playing75001000400300200300100
Percentage75%10%4%3%2%3%1%
Estimated total players15000250001200011000100001000010000
Estimated remaining players75001650031001800600200100
Remaining prizes (day start)100504742362713
Win probability0.66%0.30%1.52%2.33%6.00%13.50%13.00%


As you can see, the people playing first were screwed pretty much, because it was expected the total players to be 15000 and the distribution closer to linear. After half of them played in the first day, panic made them all increase the expected players to 25000, while thinking what to do. Then they realised that the distribution of players is affected by the fact that all play after reading their emails and then they will probably not come play anymore. They adjust the win probability every day and as you can see, it is good to play in the last days.

But what would have happened if 1) they knew the percentual distribution of players would be 75,10,4,3,2,3,1 after an email campaign and 2) the total number of players will be a percentage out of all emails sent and so they estimated 10000 people playing and the right distribution?









Day 1Day 2Day 3Day 4Day 5Day 6Day 7
People playing75001000400300200300100
Percentage75%10%4%3%2%3%1%
Estimated total players10000100001000010000100001000010000
Estimated remaining players250015001100800600300100
Remaining prizes (day start)100251511863
Win probability1.00%1.00%1.00%1.00%1.00%1.00%1.00%


Even if computing every day the number of remaining prizes over the remaining players, the probability was constantly 1%. Of course, one could say "Why didn't they stick to their 0.66% probability and be done with it? Like this:









Day 1Day 2Day 3Day 4Day 5Day 6Day 7
People playing75001000400300200300100
Percentage75%10%4%3%2%3%1%
Estimated total playersNot important
Estimated remaining playersNot important
Remaining prizes (day start)100434038373534
Win probability0.66%0.66%0.66%0.66%0.66%0.66%0.66%


Everything is perfectly honest, only that they remained with a third of prices on hand. Now they have to give them to charity and be suspected of doing this on purpose for whatever distant relative that works at that charity.

Well, think about it, and let me know what you think. Are there smarter solutions? Is there a web repository of statistical data for things like that?

and has 0 comments
The story in Claymore was pretty standard: monsters attack people, people are powerless, therefore an organization of hybrids (female warriors carrying deadly claymore swords) emerges to protect people from said monsters. So it's like Blade, in theory. But in reality it has the feel of Berserk (the first cool part, not the crappy lingering mess that it is now). Or you can imagine Naruto, with the monster and everything, fighting against a species of demon foxes. Only without the sillyness and all the mentoring.

I really liked the manga, I can barely wait for it to continue, unfortunately it is distributed like one chapter per month. The 26 episode anime series follows closely the manga story, but unfortunately ends prematurely with a different idea in the last two episodes. Not that it is not a lot better than Berserk leaving us in the dark at the end of the anime or other series that just ended in mid air.

Bottom line, if you liked Berserk, you will like this. If you like Naruto/Bleach, you will like this. I can even throw a little Akira in, to convince you, but it would probably be a stretch :)

and has 0 comments
I have found this great link in Tomáš Petříček's blog which gives a very simple and elegant solution to casting to an anonymous type.

Short story shorter:

// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T objOfTypeT)
{
return (T)obj;
}


So simple! You see that the objOfTypeT parameter is never used, but the type infered from it is!

Update:
Correct usage:Cast(obj,anonObj)
Incorrect usage:Cast(obj,anonObj.GetType())

and has 0 comments


Wee! Another Peter F. Hamilton book has been published. This time it is the second part of the Void trilogy, an ongoing series set up in the Commonwealth saga universe, but much later. Many characters are rented from said saga, so it would be a good idea to read that one first. Besides, as is Hamilton's style, the second book starts abruptly from the end of the first one and ends abruptly awaiting the third part.

And, again, like in the Night's Dawn trilogy, the plot is a combination of stories, one set in the technological future of mankind and one in a feudal, fantasy like, universe. Hamilton's talent is to combine these two in a believable common narative. They are not so linked as in Night's Dawn and, I have to admit, I like the fantasy arch better, even if it is the classic Messiah myth. Maybe because it is not contiguous, but rather made up of small stories that have a beginning and an end.

Well, either way, it was a great book and I am waiting for the third part, due to be released in far away late 2009 or even 2010 :(

and has 0 comments
First of all I want to say that I know I haven't been writing many tech articles lately and I've disappointed quite a few of the people reading this blog. I intend to rectify that, even if I am suferring from one of those dry tech spells at the moment :)

Anyway, about the oil. What if one could replicate the process that creates oil naturally, speed it up, and use it to not only for creating oil, but also for getting rid of a lot of organic waste? The technology is called Thermal Depolymerization and is pattented by the Changing World Technologies company. So, if one is to believe the Wikipedia article, while the test factory and the company itself have had problems ranging from technological hickups, to having to pay for the waste they use as fuel up to neverending complains from neighbours about the smell of bio waste, the technique was shown to work!

So, while the process does allow the production of slightly cheaper oil than the one extracted, it will certainly gain a big boost from the increase of prices in underground oil.

Here is a link to a 2003 interview with the CEO of Changing World Technologies, but utterly demolished by Paul Palmer, a chemistry PhD here. Also, this process is nothing very new or unique! there are other methods that are said to transform organic waste to Ethanol, as described in this link. So, oil may not dead yet.

I had this really old site that I was asked to "upgrade". Net 1.1 to 3.5. So I had to change old ADO.Net SqlConnection to Linq-to-Sql. A lot of unforseen issues. Sometimes it is close to impossible to recreate a simple SQL query without changing the database, as in the case of updating tables or views without primary keys.

Anyway, I got stuck in a very simple issue: How to sort a Linq query based on the string returned by the GridView Sorting event. After a lot of tries and Googling I found it was easier to use third party software (although it's more of a 2.5rd party software, as it is made by Scott Guthrie from Microsoft). Here is the link to the blog entry: Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library) . You can find there a sample project to download, with the LINQ Dynamic Library inside.

With this library and the OrderBy extension methods the code becomes:
var somethings=from something in db.Somethings....;
var data = somethings.OrderBy(Sort + " asc");
gv.DataSource=data;
gv.DataBind();

I had this calendar extender thingie in my site and the client was Italian so I had to translate it into Italian. Nothing easier. Just enable EnableScriptGlobalization and EnableScriptLocalization and set either the Web.config or Page culture settings.

However, the footer of the calendar kept showing "Today" instead of "Oggi". I checked the source and I noticed that it used a AjaxControlToolkit.Resources.Calendar_Today javascript variable to create the footer. Step by step I narrowed it down to the AjaxControlToolkit resources! Funny thing is that they didn't work. I tried just about everything, including Googling, only to find people having the opposite problem: they would have all these resource dlls created in their Bin directory and couldn't get rid of them. I had none! I copied the directories from the ACTK and nothing happened.

After some research I realized that the Ajax Control Toolkit does NOT include the option for multi language UNLESS in Release mode. I was using everything in the solution, including the ACTK, in Debug mode. Changing the AjaxControlToolkit build to Release in the solution made this work.

A new (and old) buzzword: to reinvent. It is always a good thing to reinvent yourself, they say, with the effect of relieving boredom and living a "new" life. You may discard bad or useless things in favor of good things. It is also good to reinvent something somebody else did, like a movie. You take the idea, you remove the bad things, you add good things. But, as in the case of the benevolent tyrant, the definition of good and bad is always fuzzy.

Was it good to reinvent BattleStar Galactica? I say YES! It was (and still is, despite screenwriters efforts) the best sci-fi series out there. Of course, that is my opinion. Was it good to reinvent Terminator, incarnated into a teenage girl looking machine? Ahem. But I still watch it. Was it good to reinvent Superman as a troubled teenager? Puh-lease! Come... on! Nah-uh! (See, I address the younger demographic here).

Because, you see, the people that decide what is good and bad in movies are actually the money people. They look at superficial statistics that only show... money! They make abhorent remakes of decent films (like Indiana Jones 4 - The Rape of Indiana) or they turn every hero into man/woman/teenager/animated-character/doll versions that bring nothing new.

In the case of Star Trek, they made the first low budget series than achieved cult level regardless of bad production values and some ridiculous scripts, then they made a sequel (at that time reinvention was not invented yet) where Patrick Stewart redefined the space captain as a cerebral science oriented man, but with lots of guts, then they started the old routine: make the captain black, make him a woman, replace the ship with a station, then with another ship, but in some other place, etc. They even made a prequel, which, for almost a full season, was decent in both interpretation and scenarios. What was missing, of course, was a teenage Star Trek captain. Well, no more!

"Star Trek", the 2009 movie in the making (and no doubt, with a series looming if money are made), features a young Kirk and (what a fallacy) a young Spock! The director is none other than my least favourite person in the world: J.J.Abrams, the maker of such abismal stupidities (but well received by the general audience) like Alias, Lost and Fringe. The writers are Abramses old team, Roberto Orci and Alex Kurtzman, the brilliant creators of such idiocies like Alias, Fringe and Xena/Hercules!

I am trying to keep an open mind here, but I would venture to guess that the new Star Trek will have big booming sounds whenever something strange happends, will be filled with inexplicable things that will never be explained, except maybe in the movie (but I doubt it, they have to plant the hook for a series) and will have people calling the others by name obsessively, regardless if the need for it arises. So, it may be cool, but I expect to be baktag!

and has 0 comments
I've listened to this song for a long time now, it was only proper that it would appear on my blog sooner or later. Sandra Nasic sang for Guano Apes and after the band split she released a solo album in 2007 called The Signal which features some good songs, although a little mellow for my taste. You can listen to fragments of some of Sandra's songs on her MySpace site, visit her official site or just plain google for videos like I do :)

So listen to this symphonic Sandra Nasic sound. I wish she would have done more pieces like this.


and has 0 comments
Brisingr is the third book in the Inheritance cycle (now a cycle because the author could not end the story in only three books). While I enjoyed reading it and I know that Paolini had all the best intentions writing it, I would not recommend it.

I have too little recollection of the first two books, to tell you the truth, but I do remember I was captivated by the action in them, if nothing else. The "magical technology" also had a great lure for me. In the third installment, all of these are missing or of poor quality. Roran is far more interesting than Eragon in this book, while the bad characters have lost a few dimensions (from the few they already had) and have become pathetic. T'Pol (sorry... I meant Arya) is docile and closer to the human heart, making her completely uninteresting, while the elves in general (and Oromir and Glaedr in particular) act like Asgaard on pot.

Why use StarTrek and StarGate terms to describe a fantasy book? Because it seems that's the only real inspiration of the third book of the Inheritance cycle. I could have done without the Doctor Who references in it, as well.

You can see a little YouTube video of Christopher Paolini talking about Brinsgr here, where an "unofficial" fan club is trying to earn money from said YouTube by disabling the embedding option.

A few days ago a coworker asked me about implementing an autocomplete textbox with not only text items, but also images. I thought, how hard can it be? I am sure the guys that made the AutoCompleteExtender in the AjaxControlToolkit thought about it. Yeah, right!

So, I needed to tap into the list showing mechanism of the AutoCompleteExtender, then (maybe) into the item selected mechanism. The AutoCompleteExtender exposes the OnClientShowing and the OnClientItemSelected properties. They expect a function name that accepts a behaviour and an args parameters.

Ok, the extender creates an html element to contain the list completion items or gets one from the property CompletionListElementID (which is obsoleted anyway). It creates a LI element for each item (or a DIV in case of setting CompletionListElementID). So all I had to do was iterate through the childNodes of the container element and change their content.

Then, on item selected, unfortunately the AutoCompleteExtender tries to take the text value with firstChild.nodeValue, which pretty much fails if the first child of the item element is not a text node. So we will tap in OnClientItemSelected, which args object contains item, the text extracted as mentioned above (useless to us), and the object that was passed from the web service that provided the completion list. The last one we need, but keep reading on.

So the display is easy (after you get the hang of the Microsoft patterns). But now you have to return a list of objects, not mere strings, in order to get all the information we need, like the text and the image URL. Here is the piece of code that interprets the values received from the web service:
// Get the text/value for the item
try {
var pair = Sys.Serialization.JavaScriptSerializer.deserialize('(' + completionItems[i] + ')');
if (pair && pair.First) {
// Use the text and value pair returned from the web service
text = pair.First;
value = pair.Second;
} else {
// If the web service only returned a regular string, use it for
// both the text and the value
text = pair;
value = pair;
}
} catch (ex) {
text = completionItems[i];
value = completionItems[i];
}


In other words, it first tries to deserialize the string received, then it checks if it is a Pair object (if it has a First property) else it passes the object as value and text! If deserialization fails, the entire original string is considered. Bingo! So on the server side we need to serialize the array of strings we want to send to the client. And we do that by using System.Web.Script.Serialization.JavaScriptSerializer. You will see how it goes into the code.

So far we displayed what we wanted, we sent what we wanted, all we need is to set how we want the completion items to appear. And for that I could have used a simple string property, but I wanted all the goodness of the intellisense in Visual Studio and all the objects I want, without having to Render them manually into strings.

So, the final version of the AutoCompleteExtender with images is this: A class that inherits AutoCompleteExtender, but also INamingContainer. It has a property ItemTemplate of the type ITemplate which will hold the template we want in the item. You also need a web service that will use the JavascriptSerializer to construct the strings returned.

Here is the complete code:
AdvancedAutoComplete.cs

using System;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;

namespace Siderite.Web.WebControls
{
/// <summary>
/// AutoCompleteExtender with templating
/// </summary>
public class AdvancedAutoComplete : AutoCompleteExtender, INamingContainer
{
private ITemplate _template;

[TemplateContainer(typeof(Content))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ItemTemplate
{
get { return _template; }
set { _template = value; }
}

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
const string script = @"
function AdvancedItemDisplay(behaviour,args) {
var template=behaviour.get_element().getAttribute('_template');
//if (!template==null) template='${0}';
for (var i=0; i<behaviour._completionListElement.childNodes.length; i++) {
var item=behaviour._completionListElement.childNodes[i];
var vals = item._value;
var html=template;
for (var c=0; c<vals.length; c++)
html=html.replace(new RegExp('\\$\\{'+c+'\\}','g'),vals[c]);
item.innerHTML=html;
}
}

function AdvancedSetText(behaviour,args) {
var vals=args._value;
var element=behaviour.get_element();
var control = element.control;
if (control && control.set_text)
control.set_text(vals[0]);
else
element.value = vals[0];
}
"
;
ScriptManager.RegisterClientScriptBlock(this, GetType(), "AdvancedAutoComplete", script, true);

OnClientShowing = "AdvancedItemDisplay";
OnClientItemSelected = "AdvancedSetText";
}

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string template = GetTemplate();
((TextBox)TargetControl).Attributes["_template"] = template;
}

private string GetTemplate()
{
Content ph=new Content();
ph.Page = Page;
_template.InstantiateIn(ph);
HtmlTextWriter htw = new HtmlTextWriter(new StringWriter());
ph.RenderControl(htw);
return htw.InnerWriter.ToString();
}
}
}


MainService.cs

using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Web.Script.Services;
using System.Web.Services;

/// <summary>
/// Web service to send auto complete items to the AdvancedAutoComplete extender
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MainService : WebService
{
[WebMethod]
[ScriptMethod]
public string[] GetCompletionList(string prefixText, int count)
{
JavaScriptSerializer jss=new JavaScriptSerializer();
List<string> list=new List<string>();
for (int c = 0; (list.Count< count) && (c < 100000); c++)
{
string s = (c*c).ToString();
if (s.StartsWith(prefixText))
{
object[] item = new object[] {s, "images/demo.gif"};
list.Add(jss.Serialize(item));
}
}
return list.ToArray();
}
}



An example of the use

<asp:TextBox runat="server" ID="tbMain"></asp:TextBox>
<cc1:AdvancedAutoComplete ID="aceMain" runat="server" BehaviorID="mhMain" TargetControlID="tbMain"
ServiceMethod="GetCompletionList" ServicePath="~/MainService.asmx" MinimumPrefixLength="0"
CompletionInterval="0">
<ItemTemplate>
<asp:Image runat="server" ID="imgTest" ImageUrl="${1}" /><asp:Label runat="server"
ID="lbTest" Text="${0}"></asp:Label>
</ItemTemplate>
</cc1:AdvancedAutoComplete>


That's it! All you have to do is make sure the controls in the template render ${N} text that gets replaced with the first, second, Nth item in the list sent by the web service. The text that will be changed in the textbox is always the first item in the list (${0}).

Restrictions: if you want to use this a control in a library and THEN add some more functionality on the Showing and ItemSelected events, you need to take into account that those are not real events, but javascript functions, and the design of the autocompleteextender only accepts one function name. You could create your own function that also call on the one described here, but that's besides the point of this blog entry.