| | Sun | Mon | Tue | Wed | Thu | Fri | Sat | | 29 | 30 | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 10 | 11 | 12 | | 13 | 14 | 15 | 16 | 17 | 18 | 19 | | 20 | 21 | 22 | 23 | 24 | 25 | 26 | | 27 | 28 | 29 | 30 | 31 | 1 | 2 | | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Search
Navigation
Categories
Blogroll
|

Friday, February 29, 2008
Visual Studio 2008 CSS editing and Themes
With Visual Studio 2008 there has been much fanfare about the new CSS editing features. One of the biggest complaints is that the Theme set on the page is not considered for CSS editing. But if you set the StyleSheetTheme is does work. Why?
The reason has to do with when the Theme and StyleSheetTheme objects are created in the page lifecycle, when they are applied to the page, and how that page lifecycle works differently in the designer than normal page execution.
The Theme object is essentially created at the end of the OnPreInit phase of the page lifecycle. The StyleSheetTheme, on the other hand, is created during the construction of the page.
If a Page has a Theme and/or a StyleSheetTheme these are applied during the OnInit phase of the page lifycycle. This includes applying any properties from .skin files and adding any <link> directives for any .css files.
The normal page lifecycle is not executed in the designer. In order for the designer to display the page it must instantiate the page object (and all of its controls), thus the StyleSheetTheme object is created as a side effect. Then, it seems, the designer takes special care to only call the OnInit page lifecycle method. This leaves the page without a Theme object so at this point only the contents of the StyleSheetTheme are applied. Then, of course, to display the contents of the page Render is called.
So the reason the CSS editing features in Visual Studio 2008 don’t support Themes is because the designer skips the stage in the page lifecycle where the Theme is created.
So if you want design support for your App_Theme .css and .skin files, use StyleSheetTheme. The main drawback is that StyleSheetTheme can’t be set dynamically in OnPreInit. So then if you do need dynamic theme assignment, during development set StyleSheetTheme in the <pages> element in web.config and then at deployment time remove the use of StyleSheetTheme and go back to using Theme. Too bad this is a pain in the arse.
2/29/2008 11:14:51 AM (Eastern Standard Time, UTC-05:00)

Wednesday, January 16, 2008
Visual Studio 2008 CSS editing and Themes
With Visual Studio 2008 there has been much fanfare about the new CSS editing features. One of the biggest complaints is that the Theme set on the page is not considered for CSS editing. But if you set the StyleSheetTheme is does work. Why?
The reason has to do with when the Theme and StyleSheetTheme objects are created in the page lifecycle, when they are applied to the page, and how that page lifecycle works differently in the designer than normal page execution.
The Theme object is essentially created at the end of the OnPreInit phase of the page lifecycle. The StyleSheetTheme, on the other hand, is created during the construction of the page.
If a Page has a Theme and/or a StyleSheetTheme these are applied during the OnInit phase of the page lifycycle. This includes applying any properties from .skin files and adding any <link> directives for any .css files.
The normal page lifecycle is not executed in the designer. In order for the designer to display the page it must instantiate the page object (and all of its controls), thus the StyleSheetTheme object is created as a side effect. Then, it seems, the designer takes special care to only call the OnInit page lifecycle method. This leaves the page without a Theme object so at this point only the contents of the StyleSheetTheme are applied. Then, of course, to display the contents of the page Render is called.
So the reason the CSS editing features in Visual Studio 2008 don’t support Themes is because the designer skips the stage in the page lifecycle where the Theme is created.
So if you want design support for your App_Theme .css and .skin files, use StyleSheetTheme. The main drawback is that StyleSheetTheme can’t be set dynamically in OnPreInit. So then if you do need dynamic theme assignment, during development set StyleSheetTheme in the <pages> element in web.config and then at deployment time remove the use of StyleSheetTheme and go back to using Theme. Too bad this is a pain in the arse.
1/16/2008 4:01:05 PM (Eastern Standard Time, UTC-05:00)

Wednesday, October 17, 2007
VS2008 does not allow targeting of .NET 2.0
I was chatting with Dominick today about .NET 3.5 and VS2008. One of the features of VS2008 is that you’re supposed to be able to target older versions of the .NET framework. Unfortunately I don’t think this is entirely accurate. Here’s the problem…
The .NET 3.5 framework is really just the .NET 2.0 framework (CLR engine plus system libraries) plus the 3.0 libraries and the 3.5 libraries… sort of. Actually, 3.5 patches the 2.0 framework (just as Microsoft has been doing since .NET was released) under the guise of SP1. The patching is intended to only fix bugs and security problems and is designed to be backwards compatible. This patching of the 2.0 framework is all fine and good, except in the claim that VS2008 can target 2.0.
When doing development in VS2008 with a project that targets 2.0 realize that on the developer’s machine they will be using .NET 2.0 SP1 which has new types and APIs. This means VS2008 will allow you to use those new APIs. But if you then try to deploy to a machine with only .NET 2.0 (not SP1) those APIs won’t be available. To deploy to another machine it will require .NET 2.0 SP1 to have been installed. I can just hear it now… “it works on my machine”.
Not a huge deal, but just be aware that VS2008 development allows targeting .NET 2.0 SP1 (not just 2.0).
10/17/2007 2:40:13 PM (Eastern Daylight Time, UTC-04:00)

Tuesday, July 26, 2005
ICallbackEventHandler vs AJAX.NET
There’s been much excitement recently about AJAX and how it provides a rich model for callbacks and client scripting. There’s also been much disappointment in the ASP.NET 2.0 callback implementation with ICallbackEventHandler, especially in contrast to what AJAX does.
As I see it, AJAX provides two things over and beyond ICallbackEventHandler. The first feature is arbitrary parameters to the target method. The implementation uses reflection to map the incoming call onto an arbitrary method and its parameters. This is certainly convenient. The second feature going for it is generating JavaScript objects in the client script that correspond to server side types returned from the callback method. This is also very convenient.
With those two slick features over ICallbackEventHandler, it’s easy to overlook what AJAX doesn’t do well. The primary thing that ICallbackEventHandler has over AJAX is that it integrates very well into the server page lifecycle. This might seem unnecessary and it is if all your callback method is executing code unrelated to the page object on the server (like accessing a database and returning some values, say). But, integrating into the page model is essential if you want to leverage all those server controls.
An interesting technique is to use Control.RenderControl in the callback method. This will ask the control to render itself into a buffer that you have manually constructed. The rendered HTML in the buffer will be the result of your call method. Then in the client there’s little work to do except to take the returned HTML and replace a tag’s innerHTML with those results. Although sorting is an option on the GridView, it works well as an example of this technique that can be used for almost any custom control:
In our ASPX we have a simple DataSource control and a GridView (note that we’ve disabled ViewState):
<asp:SqlDataSource runat="server" ID="_ds"
ConnectionString="<%$ ConnectionStrings:Pubs %>"
SelectCommand="select * from authors"
></asp:SqlDataSource>
<div id="_div">
<asp:GridView EnableViewState="false"
runat="server" id="_grid"
DataSourceID="_ds"
OnRowDataBound="_grid_RowDataBound">
</asp:GridView>
We’re handling the RowDataBound event so we can augment the header row with some javascript to do our callback to the server.
protected void _grid_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
foreach (TableCell cell in e.Row.Cells)
{
cell.Text = string.Format(
"<a href='javascript:SortGrid(\"{0}\")'>{0}</a>",
cell.Text);
}
}
}
The client side Sort function is what issues the callback to the server:
<script language="javascript">
function SortGrid(column)
{
<%= ClientScript.GetCallbackEventReference(this,
"column", "ShowResult", null) %>
}
</script>
The server side callback method then does its magic:
string ICallbackEventHandler.RaiseCallbackEvent(string val)
{
_grid.Sort(val, SortDirection.Ascending);
_grid.DataBind();
using (StringWriter sw = new StringWriter())
{
HtmlTextWriter htw = new HtmlTextWriter(sw);
_grid.RenderControl(htw);
htw.Flush();
return sw.ToString();
}
}
So the return from the callback method is the rendered GridView sorted based upon the callback parameter. The in the client it’s just a matter of taking that rendered HTML and merging it into the client DOM:
<script language="javascript">
function ShowResult(val, ctx)
{
document.getElementById('_div').innerHTML = val;
}
</script>
This technique makes the page more efficient because we’ve eliminated the bloated ViewState for the GridView. We post to the server only what we need for it to do its job. And the returned data is just the piece of the page that needs updating. This certainly beats reposting the entire page.
After I wrote up this sample, I started wondering how the GridView (and TreeView, for that matter) were implemented when you enable the EnableSortingAndPagingCallbacks property (or EnableClientScript for the TreeView). It turns out they do essentially the same thing. They call RenderControl on themselves and send that back to the client which is then simply replaced in the client DOM. This is definitely a useful technique.
7/26/2005 7:22:27 PM (Eastern Daylight Time, UTC-04:00)

Monday, March 14, 2005
A couple of things with cross page postbacks in ASP.NET 2.0
ASP.NET 2.0 introduces the ability to have an ASPX page postback to a different ASPX page with cross page postbacks. This was done all the time in ASP but wasn’t supported in ASP.NET 1.x. This wasn’t directly supported because on the server you need the same page to be recreated upon postback so the same controls could be repopulated with the post data. Since the model is to work at a higher level with server side controls and their properties, posting back to a different page would force you to access Request.Form to fetch the data a user had entered, which is a lower level than the control model wants.
So, in v2.0 they came up with a way to support cross page postbacks. This is enabled by a button on the first page setting PostBackUrl property to the page that will handle the postback. Once in the second page you can access the controls from the previous page by accessing the Page.PreviousPage property. Here’s a sample that’s like most of the documentation I’ve seen:
// Page1.aspx
<form id="form1" runat="server">
<asp:TextBox runat="server" ID="_tb1"></asp:TextBox>
+
<asp:TextBox runat="server" ID="_tb2"></asp:TextBox>
<asp:Button runat="server" ID="_button"
PostBackUrl="~/Page2.aspx" Text=" = " />
</form>
// Page2.aspx
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
TextBox tb1 = (TextBox)PreviousPage.FindControl("_tb1");
TextBox tb2 = (TextBox)PreviousPage.FindControl("_tb2");
int sum = Int32.Parse(tb1.Text) + Int32.Parse(tb2.Text);
_result.Text = sum.ToString();
}
</script>
<form id="form1" runat="server">
Answer is: <asp:Label runat="server" ID="_result"></asp:Label>
</form>
I find this to be entirely too tedious primarily because this approach still loses out of the declarative server side object model. The second page has to re-declare the same controls as local variables to access the properties. I don’t think it will be how people write their second page to handle the postback. Instead the more useful approach will be to use the <%@ PreviousPageType %> directive in the second page:
// Page1.aspx
<script runat="server">
public int Sum
{
get
{
return Int32.Parse(_tb1.Text) + Int32.Parse(_tb2.Text);
}
}
</script>
<form id="form1" runat="server">
<asp:TextBox runat="server" ID="_tb1"></asp:TextBox>
+
<asp:TextBox runat="server" ID="_tb2"></asp:TextBox>
<asp:Button runat="server" ID="_button"
PostBackUrl="~/Page2.aspx" Text=" = " />
</form>
// Page2.aspx
<%@ PreviousPageType VirtualPath="~/Page1.aspx" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
_result.Text = PreviousPage.Sum.ToString();
}
</script>
<form id="form1" runat="server">
Answer is: <asp:Label runat="server" ID="_result"></asp:Label>
</form>
The first page utilizes the posted data via the declarative controls and it provides the necessary information to the second page a public property. Now this is much better since we now get to reuse the declarative controls. I really think this will be the preferred style of using cross page postbacks in ASP.NET 2.0.
One very interesting thing I’ve noticed about cross page postbacks is the life cycle of the first page when posting back to the second. The first time the second page accesses Page.PreviousPage ASP.NET needs to make a page object available. So it, in essence, creates the Page.PreviousPage object and calls ProcessChildRequest, which is similar to ProcessRequest except it stops processing prior to PreRender and a fake Response object is created so that no Writes are emitted. This has some interesting side effects, one of which is that all of the server side events of the first page fire. This includes Page_Init, Page_Load and any control events like Button.Click events (if the Button has an OnClick event declared). This blew me away and it’s certainly something to keep in mind when using cross page postbacks. One way to detect if your page is being accessed as a PreviousPage is to check Page.IsCrossPagePostBack.
One last thing to note about cross page postbacks is that using tracing is a PITA, since the PreviousPage’s Trace messages end up mixed with the current page’s Trace messages. I submitted a request to the product feeback center to see what they could do about it.
3/14/2005 5:10:57 PM (Eastern Standard Time, UTC-05:00)

Saturday, February 19, 2005
Dynamic thumbnail images from ASP.NET
I have had this sampe code of dynamic thumbnail generation kicking around for some time, so I've finally gotten the time to post it here. This sample code is an IHttpHandler implementation that reads a JPG from the filesystem and dynamically generates a thumbnail sized version of the image and emits that to the response stream. What I like about this approach is that you don't need to create a file on the filesystem for the thumbnail as it's all done in memory. This really shows how cool (and useful, of course) IHttpHandler is. Here's the gist of the implementation:
public class ImageHandler : IHttpHandler
{
// the max size of the Thumbnail
const int MaxDim = 120;
public void ProcessRequest(HttpContext ctx)
{
// let's cache this for 1 day
ctx.Response.ContentType = "image/jpeg";
ctx.Response.Cache.SetCacheability(HttpCacheability.Public);
ctx.Response.Cache.SetExpires(DateTime.Now.AddDays(1));
// find the directory where we're storing the images
string imageDir = ConfigurationSettings.AppSettings["imageDir"];
imageDir = Path.Combine(
ctx.Request.PhysicalApplicationPath, imageDir);
// find the image that was requested
string file = ctx.Request.QueryString["File"];
file = Path.Combine(imageDir, file);
// load it up
using (Image img = new Bitmap(file))
{
// do some math to resize the image
// note: i know very little about image resizing,
// but this just seemed to work under v1.1. I think
// under v2.0 the images look incorrect.
// *note to self* fix this for v2.0
int h = img.Height;
int w = img.Width;
int b = h > w ? h : w;
double per = (b > MaxDim) ? (MaxDim * 1.0) / b : 1.0;
h = (int)(h * per);
w = (int)(w * per);
// create the thumbnail image
using (Image img2 =
img.GetThumbnailImage(w, h,
new Image.GetThumbnailImageAbort(Abort),
IntPtr.Zero))
{
// emit it to the response strea,
img2.Save(ctx.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
public bool IsReusable
{
get { return true; }
}
private bool Abort()
{
return false;
}
}
2/19/2005 12:43:03 PM (Eastern Standard Time, UTC-05:00)

Tuesday, February 15, 2005

Wednesday, January 05, 2005
OR Mappers or RO Mappers
A lot of people (myself included) feel the need to use OR Mappers to save development effort. Sometimes those people even build their own OR Mappers J. Well, I’ve built one too (like everyone else out there, practically). But I don’t quite think I’ve built an OR Mapper as much as I’ve built a RO Mapper. Perhaps this is a silly point to make, but what I’ve done isn’t taken an object model then mapped it onto how the database happens to be laid out (by say a DBA). No, what I’ve done is I started in the database myself, built my schema, and then built a framework to map from the database model into my object model. So, I guess that’s why it’s more or an RO Mapper, as opposed to an OR Mapper.
Anyway, this post is to put out my sample implementation for others to look at if interested. And when it comes down to it, I’d sometimes think of this sample as more mental masturbation in what one can do with reflection and late binding than trying to build a high performance database mapping layer. Oh well. So the link to the sample if above and contains 2 zips, one for v1 and one for v2 (which uses generics and nullable types).
So, to create the mapping from my database schema to my class model, I author a class to hold the columns from the database as such:
[DBTable("authors")]
class Author
{
[DBColumn("au_id", PrimaryKey=true)]
public string SSN;
[DBColumn("au_fname")]
public string FirstName;
[DBColumn("au_lname")]
public string LastName;
[DBColumn("phone")]
public string Phone;
[DBColumn("address")]
public