February 2007 - Posts

Hosting ASP applications in IIS 7
Mon, Feb 26 2007 4:49

Today I needed to configure IIS 7 to host an old classic ASP application. I was facing a permissions problem when i tried to access an Access DB (which persisted even after I've given full control to the directory where the ASP application was installed). I was able to solve this problem after giving permissions to the temp dir of the network service account. This Kb gives you all the info you need on this.

by luisabreu | with no comments
Filed under:
65 math books available online for free
Thu, Feb 22 2007 15:26

Here they are [via Signs on the Sand]

by luisabreu | with no comments
Filed under:
AJAX client files should be separated into smaller units
Thu, Feb 22 2007 15:07

Yep, that's what i expected to happen but it didn't...I think that the main ajax client file (MicrosoftAjax.js) should be separated into several files. even though saying that having only a single file might give you a quicker download time (which might be true if you want to get everything), i don't buy it. for instance, in my current project , i'd really really love to use OO introduced by AJAX extensions client library. But that's all I want for this project. I don't really need components or the network stack. Unfortunately, everything is packed on the same file. If I want to use the "AJAX Extensions OO approach", I do need to download everything.

Oh well, I'll just have to keep using the traditional javascript OO code (which really isn't much fun)...

by luisabreu | 6 comment(s)
Filed under:
Reflector 5.0 follow up
Wed, Feb 21 2007 13:35

After posting about the new release of reflector, I've just noticed that there's a ppt file that gives you all the details of the new release.

by luisabreu | with no comments
Filed under:
Reflector 5.0 is out
Tue, Feb 20 2007 13:11

Lutz has done it again. The new release has several cool features, some of which are presented in this post by Scott Hanselman.

A few years ago, there was a site made by MS called Software Legends (unfortunately, it seems like it's no longer available) where you could see several important people that do really know a lot of "MS things". I think that by now, Lutz should be put in a completely new category. Maybe something like super-cool software legend? what do you think?

by luisabreu | 1 comment(s)
Filed under:
Adding controls to an UpdatePanel through code
Thu, Feb 15 2007 16:21

[Update: Thanks to Cyril, I've update the code to use the new AsyncPostbackSourceElementID]

In the final version the UpdatePanel has a new cool property (ContentTemplateContainer) which really helps you if you want to add controls to an UpdatePanel through code.

Lets illustrate the usage of this property with a simple page that changes the content of an UpdatePanel when the user clicks on a button. Let's  start by presenting the 2 user controls used in this example:

control1.ascx

<%@ Control Language="C#" ClassName="control1" %>
<script runat="server">
  void HandleClick1(object sender, EventArgs e)
  {
      lbl.Text = txt.Text;
  }
</script>

This is user control 1.
Name: <asp:TextBox runat="server" id="txt" />
<asp:Button runat="server" id="bt" Text="Print name" OnClick="HandleClick1" />
<br />
<asp:Label runat="server" id="lbl" />

 

control2.ascx

<%@ Control Language="C#" ClassName="control2" %>
This is user control 2: <%= DateTime.Now.ToString() %>
<asp:Button runat="server" id="bt" Text="Refresh" />

page.aspx

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  protected override void OnLoad(EventArgs e)
  {
      base.OnLoad(e);

      if( manager.IsInAsyncPostBack )
      {
            string info = manager.AsyncPostbackSourceElementID;
            if( string.CompareOrdinal(info, bt.UniqueID) == 0)
            {
                    CurrentControl = CurrentControl == "control1.ascx" ? "control2.ascx" : "control1.ascx"
            }
            
            string info = this.Request.Params[manager.UniqueID];
            if( info.IndexOf("|") > 0 )
            {
                  string ctlId = info.Substring(info.IndexOf("|") + 1);
                  if( string.CompareOrdinal(ctlId, bt.UniqueID) == 0)
                  {
                    CurrentControl = CurrentControl == "control1.ascx" ? "control2.ascx" : "control1.ascx"
                  }
             }
      }
      LoadControl();
  }

   protected string CurrentControl
   {
       get
       {
          return ViewState["CurrentControl"] == null ? "control1.ascx" : (string)ViewState["CurrentControl"];
       }
       set
       {
           ViewState["CurrentControl"] = value;
       }
   }
   void LoadControl()
   {
        Control ctl = LoadControl(CurrentControl);
        panel1.ContentTemplateContainer.Controls.Clear();
        panel1.ContentTemplateContainer.Controls.Add(ctl);
    }

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
 <head runat="server">
   <title>Untitled Page</title>
 </head>
 <body>
    <form id="form1" runat="server">
           <asp:ScriptManager runat="server" id="manager" />
           <asp:UpdatePanel runat="server" id="panel1">
              <Triggers>
                 <asp:AsyncPostBackTrigger ControlID="bt" />
             </Triggers>
           </asp:UpdatePanel>
           <asp:Button runat="server" id="bt" Text="Change control" />
</form>
</body>
</html>

Yep, that's it. the tricky part is remembering that you must add dynamicaly generated controls until the end of the Load event or you might not get the expected results. Doing it on the Init event won't do you any good either because we're maintaining the current selected item on the viewstate (which is loaded after that event has fired). So, the Load even will be just fine for this.

Unfortunately, the ScriptManager control still doesn't have a property that let's you easily know the control that started an async postback. Fortunately, we do have Fiddler. with it, it's easy to see that there's a "secret" field that is being sent back to the server on the body of the request. This field is identified by the Id of the ScriptManager and you use it to get the ID of the control responsible for the postback:

manager=manager|bt&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUJNzUzMjU3MTgzZGQ6YfDv2DwDFkdpUAnK5uj8PifsMg%3D%3D&ctl03$txt=&__EVENTVALIDATION=%2FwEWBAL7vsHoDgLMhYXhDQL46LbdBgK%2B79rvDBiOVPIc%2BzmCL7ifp3dWkDx8CElm&bt=Change%20control

And now everything looks easy, right? :)

I was wrong about this one. ScriptManager does expose a property (AsyncPostbackElementSourceID) which lets you get access to the control that started the partial postback. One thing you must keep in mind: if you handle the Init event (instead of the load event) you'll have to resort to the previous code which is striked out.

by luisabreu | 10 comment(s)
Filed under:
Detecting admin elevation in PowerShell
Thu, Feb 15 2007 15:08

Though i really don't like the new UAC much (yes, I agree that it's a necessity, but I still don't like it :)), I'm trying to use it again lately. Another thing I'm trying to do is relearning PowerShell. Ian has posted a great article on how you can use configure your shell so that you know when you're running it as admin or as a regular user (do note that this is not as simple as you may be thinking due to the UAC).

by luisabreu | with no comments
Filed under:
Printing for the TLP2844 Zebra
Tue, Feb 13 2007 15:18

[You can dowload some demo code at the end of the post]

Last week I had to find a way to print to  TLP 2844 Zebra printer from a C# Windows Forms app. For those that don't know, I'm speaking about a thermal transfer printer which is normally used for printing bar codes in labels. I had to perform the following tasks:

  1. write text in the label;
  2. write bar codes to the label;
  3. print images in the label.

This specific printer understands EPL2 and expects to receive one or more commands in text. If you go through the manual, you'll see that there's several things you can do, like build forms (which are useful when you're using variables), print barcodes and even print images (which is really the hard part). For instance, if you want to print Testing, you'll have to send something like this to the printer:

A10,10,0,0,1,1,1,N,"Testing"

If you have zebra and want to run a simple test, then save the following to a txt file:

<-
N<-
A10,10,0,0,1,1,1,N,"Testing"<-
P1<-

The previous file has a blank empty line followed by the N command (which clears the buffer of the printer)and then prints one copy (P1) with the text Testing at 10,10 (x,y). Sending the previous file to the printer is as simple as copying it to LPT1 (assuming you've installed your printer in that port):

copy demo.txt lpt1:

After this short introduction, it's easy to see that we need to:

  • abstract the printer commands
  • write some code that communicates with the printer 

Abstracting the printer commands, can be easily done. In my case, I've just created an interface that looks like this:

public interface ICommand
{
    string GetCommandString();
}

and then it was just a matter of creating several classes that implement this interface. For instance, the PrintTextCommand looks like this:

public class PrintTextCommand:BasePositioning, ICommand
{
   private string _txt;
   private int _fontSelection;
   private PrintingRotation _rotation;
   private PrintingMultiplier _horizontalMultiplier;
   private PrintingMultiplier _verticalMultiplier;
   private PrintingReverse _printingReverse;
  

    public PrintTextCommand( int x, int y, string txt, PrintingRotation rotation, int fontSelection,
         PrintingMultiplier horizontalMultiplier, PrintingMultiplier verticalMultiplier, PrintingReverse printingReverse)
        :base(x, y)
    {
       _txt = txt;
       _fontSelection = fontSelection;
       _rotation = rotation;
       _horizontalMultiplier = horizontalMultiplier;
       _verticalMultiplier = verticalMultiplier;
       _printingReverse = printingReverse;
   } 

  public PrintTextCommand( int x, int y, string txt, int size)
     :this(x, y, txt, PrintingRotation.NoRotation, size, PrintingMultiplier.One,
                PrintingMultiplier.One, PrintingReverse.N)
  {}

  public PrintTextCommand( int x, int y, string txt)
     :this(x, y, txt, 2)
  {}

  #region ICommand Members

   string ICommand.GetCommandString()
   {
        return string.Format("A{0},{1},{2},{3},{4},{5},{6},\"{7}\"\n",
            _pt.X, 
            _pt.Y,
            (int) _rotation,
            _fontSelection,
            (int)_horizontalMultiplier,
            (int)_verticalMultiplier,
            PrintingReverseMapper.Map(_printingReverse), 
           _txt);
   }

  #endregion
}

Since all of the commands need to specify their location, I've created a base class (BasePositioning) which is only used to hold the topleft point used by all the commands (yes, I'll probably burn in hell for not defining a protected property and letting the derived classes access the internal field directly :)). Now, the most difficult of the commands was the one responsible for printing the image. When you think about zebra and images, you have 2 options: you can load the image in the printer's memory or can just send it each time you need to print it. In my case, I decided to go with the 2nd option since I really dind't want to go to all the sites where the code was going to be used in order to add the image to the memory of the printer (nor was I in the mood to write an installer that did just that).

Unfortunately, the EPL2 manual falls short and really won't help you much when you decide to use the GW command. Don't believe me, here's what it has to say about sending graphics to the printer:

GW Command - Direct Graphic Write

Description: Use this command to load binary graphic data directly into the Image Buffer memory for immediate printing. The printer does not store graphic data sent directly to the image buffer. The graphic data is lost when the image has finished printing, power is removed or the printer is reset. Commands that size (Q and q) or clear (N and M) the image buffer will also remove graphic image data.

Syntax: GWp1,p2,p3,p4DATA

btw, note that it's missing the , char after p4. as you'd expect, p1 and p2 is the top-left coordinate. p3 is supposed to be the width of the image in bytes and p4 its height. Well, they don't even give you a simple example of how to use this command. After loosing some time trying to find a sample, i thought it was time to learn something about images. Bob Powell's site was great because it gave me what i needed: several samples and FAQs that explained several aspects related with GDI+ and graphics - it even a sample on how to convert an image to a 1bpp image (which is really the only kind of image i was interested in).

Going back to the command help, it said that p3 was the width of an image in bytes. After going through Bob's FAQ, it was clear that after creating a Bitmap you could call the LockBits method to lock the bitmap in memory. When you do that, you end up receiving and instance of BitmapData which has several members that are important for getting the info I needed to send to the printer. For instance, the class exposes a property called Stride which returns the correct length in bytes of each line of the bitmap image (right what was needed for the p3 parameter!). The stride is important because without it you don't know where each line of the bimap starts and ends (don't forget that, in memory, the bitmap is just a plain array- Bob explains it well, so go there to get more info on what I mean). Before you start thinking that  getting the stride is a waste of time because you already know the width of the image in pixels, don't forget that you also need to know the pixel format you're using in order to get that width in bytes(for instance, in my case I got lucky because I only needed to print 1bpp images). Another thing you need to keep in mind is that the stride will always be equal or bigger than the width of the image in bytes. That's because strides are always multiples of 4 bytes (at least, in 32 bits machines). If you're really lucky, you'll get images whose width (in bytes) is also a multiple of 4. If that doesn't happen, then you do need to write more code to get the correct result printed in the Zebra. But I'll speak about this in a minute.

So, since I had all the info I needed, it was time to write the Print1bppImageCommand. I'm only showing the GetCommandString method:

string ICommand.GetCommandString()
{
  BitmapData bits = _bmp.LockBits(new Rectangle(0, 0, _bmp.Width, _bmp.Height),
  ImageLockMode.ReadOnly, _bmp.PixelFormat);

  byte[] imageBytes = new byte[bits.Height*bits.Stride];
  Marshal.Copy(bits.Scan0, imageBytes, 0, bits.Stride*bits.Height);

  int imgWidth = bits.Stride;
  int imgHeight = bits.Height;
  _bmp.UnlockBits(bits);

  return string.Format("GW{0},{1},{2},{3},{4}\n",
        _pt.X,
        _pt.Y,
        imgWidth.ToString(),
        imgHeight.ToString(),
        Encoding.GetEncoding(1252).GetString(imageBytes));

}

As you can see, it's really simple: After locking the bitmap, I create a new byte array and use the Marshal.Copy method to copy all the image bits into that array. Yes, I could have optimized the code and worked with direct pointers. I'll leave that to you though ;)

what's important to note is that I use the stride and the height of the bitmap to get the correct size of the buffer used to hold the bytes of the image. Another important thing: I'm using the 1252 encoding in order to copy the byte array to the string that is going to be sent to the printer (if you try to use ASCII, it simply won't work - I guess that I could try to use the ANSII encoding - value 0, if i'm not mistaken - but since it worked well with this, I just went along and used it).

The 1st image I've used printed without any problems...since "I was the king of the world", I decided to run a small demo for fellow workers. Guess what: I decided to choose another image and after printing it, i noticed a weird black bar on the right. what could it be? Remember me saying that the stride is always bigger or equal to the image width (in bytes)? Yep, that was the problem. You see, the 1st image was a "good one" because the stride was equal to its width. That didn't happen in the 2nd case. In my case, solving this problem is easy. Since I'm printing 1bpp images and i was sure that their size was a multiple of 8 (since I'm using 1 bit per pixel image, that means that 8 pixels will be stored in a byte), I knew that i only needed to "clear" those extra bytes. In this case, clearing means setting the color to white (which really means setting the byte in the array to 255). That's why I inserted the following code before the string.Format:

int realWidth = bits.Width/8; //only works for fixed size 1bpp images where width % 8 == 0
if( realWidth != imgWidth )
{
  int bytesToClear = imgWidth - realWidth;
  for( int i = 0; i < imgHeight; i++ )
  {
     int pos = realWidth + imgWidth * i;
     for( int counter = 0; counter < bytesToClear; counter++, pos++ )
     {
        imageBytes[pos] = 255;
     }
  }
}

And that's it! My 1bpp image is getting correctly printed. If you have a colored image, then you need to go to Bob's site and see how you can convert it to a 1bpp pixel. Btw, note that if you do need to do that, you might also need to clear individual "bits" (instead of bytes).

After finishing these commands, I only needed to create the Label base class that is responsible for letting you define several ICommands which can be sent to the printer.

After having this code working, it was only a matter of building the correct code for sending it to the printer. This time, I got lucky and found this article in codeproject. I just needed to change it slightly so that it used the same enconding I was using to save the image bytes in the string that is going to be sent to the printer.

You can download my wrappers and demo code from here.

by luisabreu | 32 comment(s)
Filed under:
PowerShell: getting along with cmdlet
Mon, Feb 12 2007 15:40

As I've said in the previous post, cmdlets can be seen as the working unit of this new shell. If you're starting with Powershell, you should start by seeing the available cmdlets. This can be easilly done through the get-command cmdlet:

PS :> get-command

After running this command, you'll get a list of all the cmdlets that have been installed in PowerShell. Another usefull cmdlet is get-help. You can use it to get info on another cmdlet. for instance, if you run the following:

PS :> get-help get-command -detailed

you'll get all the info associated with the get-command cmdlet. These 2 cmdlets should be enough to get you busy on the next hours since they let you explore all the available cmdlets.

by luisabreu | with no comments
Filed under:
Restarting Power-Shell
Mon, Feb 12 2007 9:59

After downloading and installing it in Vista, I've finally restarted learning it. A long time ago, I used this shell and really enjoyed it. Those that read the PT blog should remember the Monad series I've written at the time. Since I really don't remember many of the things I used to know, I've thought that it would be a good idea to write something about it here. By doing this, I'll keep reserving at least an hour each two days to try things out and then I'll put some notes about it here.

So, what is PowerShell? In practise, I think it can be seen as a shell that lets you use .NET objects. This means that now you can do some cool stuff from the command line since all commands receive and return objects. Btw, commands are no longer called commands. This new shell introduced the notion of command-let (aka cmdlet). According to the docs, a cmdlet is a "simple, single-function command-line tool built into the shell". In practise, you may end up writing several cmdlets to perform specific tasks.

it's all for now. In the next post I'll start writing some examples.

by luisabreu | with no comments
Filed under:
Debugging AJAX Extensions server side code
Mon, Feb 12 2007 7:32

When you install the code, you already have the option to say that you want to debug the server side code. Let's say you didn't choose that option: now what? how do you debug through the AJAX server side code? Well, you just need to change some settings in the Visual Studio IDE. After opening the IDE, choose:

Tools->Options->Debugging->Symbols and then add an entry on the Symbol file locations that points to the folder where the AJAX Extensions pdb file is.

After doing this, you just need to open the source file you're interested in debugging and set a breakpoint in the palce you want the debugger to stop. and that's it for 32 bits system. Unfortunately, I still haven't been able to put this to work in vista 64 bits. If anyone has any clues, please let me know. thanks.

by luisabreu | 1 comment(s)
Filed under:
Pay attention to the 1st parameter of the Completed event...
Sun, Feb 11 2007 9:08

that is generated by the WebRequest class. Against all odds, the 1st parameter that a method that handles this event receives is not of type WebRequest as you might expect. I say might expect because the client event system is supposed to mimic the .NET event system, where the 1st parameter passed to a method that handles the event is always the object that fired the event.

As you've certainly discovered (specially if you've handled the event), the 1st parameter passed to the event is a reference to the executor that was responsible for executing the request.  Though i really don't like it, this approach has advantages too. For instance, most of the times you want to get a reference to the executor that was responsible for the request and with this approach you have a direct reference to the executor (without needing to access the property of the WebRequest object you're using o perform the call).

However, I still would have prefered to receive a WebRequest object (instead of the reference to the executor)  because the event that i'm handling is fired by the WebRequest class. Yes, it's true that this event is *really* raised by the executor (_onReadyStateChange), but since the event is exposed by the WebRequest class, I really really really do think that we should get a reference to an instance of that class. Just my 2 cents.

by luisabreu | with no comments
Filed under:
The UpdatePanel control can't make miracles
Sat, Feb 10 2007 17:14

Most of you already know my opinion about this control: it's good, but if you're really into AJAX, you should use a client based approach. Now back to the main topic of this post. What will happen when the following page runs:

<form id="form1" runat="server">
 <asp:ScriptManager runat="server" id="manager" />
   <asp:Multiview id="m" runat="server" ActiveViewIndex="0">
     <asp:View runat="server" id="v1">
        <asp:UpdatePanel runat="server" id="panel">
           <ContentTemplate>
               <asp:button runat="server" id="bt" Text="Change view???" onclick="Process" />
           </ContentTemplate>
        </asp:UpdatePanel> 
     </asp:View>
     <asp:View runat="server" id="v2">
        <asp:UpdatePanel runat="server" id="UpdatePanel1">
           <ContentTemplate>
               view 2
           </ContentTemplate>
        </asp:UpdatePanel>
      </asp:View>
 </asp:Multiview>
</form>

And yes, from a button click I want to change the view  presented to the user... btw, I've also seen some variations which try to set the UpdateMode of both panels to Conditional.

well, this simply doesn't work. Let's see what happens when the user clicks on the bt Button:

  1. the buttons starts a postback
  2. the postback is intercepted by the PageRequestManager object
  3. since the button is inside an UpdatePanel, the full postback will be cancelled and we'll have a partial postback
  4. in the server side, the MultiView will generate the HTML for view 2
  5. while trying to process the returned HTML code on the client side, you'll get an exception because there's no UpdatePanel1 in the list of registered panels (remember: during the initial generation of the page, only the 1st UpdatePanel was rendered and that's why PageRequestManager will only have that panel in its internal list)

Since I've mentioned it before, setting the UpdateMode migh give you a corrupted viewstate instead of the error I've described before.

After following the previous steps, it's really simple to understand why this sort of approach really doesn't work. If you want to dinamically change your view, just wrap the entire MultiView control with an UpdatePanel.

by luisabreu | 3 comment(s)
Filed under:
WPF/E: Feb CTP is out
Sat, Feb 10 2007 7:47

I think i'm late again, but i've just noticed yesterday that the February release is already out!

by luisabreu | with no comments
Filed under:
Alessandro (aka Garbin) has finally anounced it!
Fri, Feb 9 2007 15:05

Alessandro (aka Garbin) has finaly announced his "secret" project. He's writing a book (with 2 other experts) on ASP.NET AJAX  Extensions. So, if you're looking for a good book in english about ASP.NET AJAX Extensions, this is it (btw, don't forget that if you're a portuguese native speaker, then you might also consider my portuguese book which will be out in March - sorry, but i couldn't resist :) ).

by luisabreu | with no comments
Filed under:
MS Research video
Thu, Feb 8 2007 17:02

My good friend Paulo sent me this cool link with some demos from MS Research. Cool stuff!

by luisabreu | with no comments
Filed under:
Inserting scripts from the server side during a partial postback
Thu, Feb 8 2007 8:11

Today I've noticed that there are some new things in this area. It seems like now there's an overload which takes a parameter of type Page (instead of Control) and when you use it, you can be sure that your javascript code will always be inserted in the page. To me, this is good news!

Another thing I've noticed is that when you use the method that receives  a Control as parameter, you can now pass an UpdatePanel. In these cases, the code will be inserted in the client side if the UpdatePanel you've passed to the method is refreshed during that partial postback.

by luisabreu | with no comments
Filed under:
Legacy mode not supported on pages that use UpdatePanels, but...
Mon, Feb 5 2007 16:50

you can still use it at your own risk.

By default, if you set the conformance level to debug, you'll get full postbacks in your pages. why? well, because during the Init event of the page, the PageRequestManager server class initializes the SupportsPartialRendering property of its owner (whic, btw, is the ScriptManager control) by checking the value of the EnableLegacyRendering (which icomes from the property with the same name that is exposed by the ScriptManager control).

What you might not know is that if you set the SupportsPartialRendering property the previous execution logic never takes place and you'll get partial postbacks working at your own risk (might I add:) )

by luisabreu | 2 comment(s)
Filed under:
Finally! IDx stands for Internal Developer
Mon, Feb 5 2007 14:34

Thanks to António Cruz for giving me the answer to my previous question. Btw, he's quoted Jason Olgon on a comment in my PT blog (since it's in english, you can read the justification for the name on the PT blog). Thanks again Antonio (I'll sleep better now that I Know ;) )

by luisabreu | 1 comment(s)
Filed under:
Getting a full postback from within an UpdatePanel without using a PostbackTrigger
Thu, Feb 1 2007 16:23

Remember those old movies where there was someone bragging and saying something like "hey, look! no Hands!" while riding a bike (or something like that)? Well, I'm going to do something similar :) Look at me: only one hand (sorry, but it looks like Vista's voice recognition isn't still working out as it should and, that being the case, I do need one hand to write :)), no postback triggers, a link button within an UpdatePanel and a full postback. Don't believe me? Run this code:

<%@ Page Language="C#" %>
<html>
 <head runat="server">
    <title>Untitled Page</title>
 </head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager id="manager" runat="server" />
         <asp:UpdatePanel runat="server" id="panel">
              <ContentTemplate>
                <asp:LinkButton runat="server" Text="Full postback" />
              </ContentTemplate>
          </asp:UpdatePanel>
  </form>
</body>
</html>

Ok, I cheated :). the truth is that I'm using both hands (which means that you'll be getting a full postback with the previous sample).

Next question: why? well, simply look at the code you're getting on the client (only  the LinkButton control):

<a href="__doPostBack('ctl03','')">Full postback</a>

Noticing anything strange? I do! note that even though the server control generates an ID it will only be inserted on the client HTML control if you explicitly set the ID porperty on the server control. So, if you add the ID to the control everything works ou as expected. If you don't, then the PageRequestManager won't be able to find the control (remeber, it doesn't have an ID and all the work that is done is by the PageRequestManager is based on finding the control through the ID)

Good news to the AJAX team: this isn't really your fault!

Bad news to the ASP.NET team: this is your fault!

If you really think about it, the AJAX team can be seen as subset of the ASP.NET team :) ...

 [Update: I've dropped the javascript prefix from the previous excerpt ]

by luisabreu | 11 comment(s)
Filed under:
More Posts Next page »