Skip Navigation Links
Search site. 
Powered by Google
Darren Neimke (Me)

My Book

Readify

">ASP.NET MVP


Interesting Portals 

NetVibes
This portal feels similar to PageFlakes in many ways but I love their gallery. They also have a feature whre certain chrome elements only become visible when you hover over the web part.

Xtra
A New Zealand news portal. I especially liked the content rotator web part at the top of the middle row. Seems like a nice way to allow a user to browse through data.

 

Posts Archive 

Posts for: Nov 2006

Keyvan Nayyeri : BlogML 2.0 Can Run on Mono

Good news!  Apparently BlogML 2.0 is primed for Mono-time smile_nerd 

Link to Keyvan Nayyeri : BlogML 2.0 Can Run on Mono

posted on 11/28/2006 8:31:03 AM ( 1 Comments )


Mad World

posted on 11/27/2006 10:40:50 PM ( 0 Comments )


Water usage per household

I finished a recent blog entry with the question: "how much water do you think that the average household uses per day?"

While trying to locate the answer for this I discovered this site.  That site contains a particularly useful calculator named the Water Efficiency Calculator that allows you to run scenarios to see how much water is used by daily household operations.

According to the ACT water board, the daily average water usage for a Canberran household is currently 900 litres with a current target to reduce that amount to 675 litres.  It's amazing to think that every household (average) in Canberra uses that amount of water.  According to our latest water bill, our daily average consumption was 680 litres so we are obviously doing something right - probably due to the lack of water that we apply to the garden. smile_regular   Recently we've started recycling a lot of our shower water which has allowed us to pump roughly 30 days of recycled water into the garden.

posted on 11/27/2006 8:48:55 AM ( 2 Comments )


Fixing Broken Web Parts

When I was writing my book I got to the 2/3 review phase and I received some feedback that I needed to include a chapter on deployment. smile_eyeroll  Nearly every book that you read seems to have the obligatory chapter on deployment and I didn't want to head down that well documented path - so I put on my thinking cap to ponder how I could satisfy these requests while not rewriting the most written chapter in book history. smile_thinking

As I thought about it, I realized that this was a great opportunity to look at the deployment of an ASP.NET 2.0 site from a different angle.  What I decided to do was to write a chapter on how to create a portal that could be easily supported when it was in production.  This is very different to forcing myself to come up with 10,000 words about what is essentially Copy/Paste. smile_regular

I wrote yesterday that one of the features that I wrote about in Chapter 9 was a significant new feature named Health Monitoring.  In another section of Chapter 9 I wrote about allowing users to remove broken web parts from a web page.  Here's the scenario:

You're running a portal page and over time you have made a significant number of personalization changes to the page.  You've added web parts to it, you've moved them around, and made other customizations too.  One day a new web part appears in the web part gallery and you add it to your page.  This web part has some logic errors in its Render method and upon adding the web part to your page you are presented with the all too familiar error page of death!  At this time the broken web part has been saved with the personalization data for the page and there is no way to display the page to remove the broken part - you're screwed!

In Chapter 9 I took a sample that Mike Harder presented at last year's PDC where he showed how to allow users to self-correct pages that had fallen to this despicable fate.  Mike showed that you could create a specialized Custom Error Page that the user would be directed to that would list all of the web parts on the page that they had come from and allow that user to manually remove web parts from that page.  Here's a picture of what that page looks like:

Repair broken pages from a custom error page

Here you can see that the user can click the button that appears next to each web part to remove web parts from the faulty page.

One of my readers pointed out that I didn't supply a working code demo for how to get this sample working and so I've created a small sample project that you can download and run to play with this scenario to see how it works.  The demo code is located here:

     Web Part Management Sample

posted on 11/26/2006 1:29:04 PM ( 0 Comments )


Health Monitoring Sample for Web Parts in Action

One of my readers wrote to me today to let me know that I hadn't included a sample for the Health and Activity Monitoring stuff that I wrote about in Chapter 9.  Health Monitoring is a really cool feature of ASP.NET 2.0 that allows you to raise events and configure the providers for them.  I've created a working solution of the concepts that are discussed in Chapter 9 which can be downloaded from here:

http://markitup.com/BookCodeSamples/HealthMonitoring.zip

In the sample a Health Event is raised when a web service takes too long to return:

OPMLService.OPMLService service = new OPMLService.OPMLService();
Stopwatch watch = new Stopwatch();

watch.Start();
string message = service.GetOPML();
watch.Stop();


if (watch.ElapsedMilliseconds >= 2000)
{
    ExternalCallWebEvent ev = new ExternalCallWebEvent(
        string.Format(
            "The call to OPMLService took {0} milliseconds to complete.",
            watch.ElapsedMilliseconds
        ),
        this,
        WebEventCodes.WebExtendedBase + 1
        );

    ev.Raise();

}

string xml = "<pre>" + Server.HtmlEncode(message) + "</pre>";
LiteralControl lit = new LiteralControl(xml);
this.Controls.Add(lit);

The ExternalCallWebEvent class is a custom event and it is configured in the Web.config file to be used with the standard Windows Event Log provider:

<healthMonitoring enabled="true">
  <eventMappings>
    <add name="WebServiceCallEvent" type="ExternalCallWebEvent" />
  </eventMappings>
  <rules>
    <add name="ServiceCallRule"
         eventName="WebServiceCallEvent" provider="EventLogProvider" />
  </rules>
</healthMonitoring>

When the page in the sample is run, you can open the Windows Event log to see details of the event:

 

Windows Event Log

posted on 11/25/2006 9:40:41 PM ( 0 Comments )


Ajax : Ajax Images - SWiK

A page full of images to use on Ajax sites Asynchronous postback image

Link to Ajax : Ajax Images - SWiK

posted on 11/14/2006 1:12:05 PM ( 2 Comments )


Now I'm a real Mo 'bro

Last month I mentioned that during Movember (the month formerly known as november) I'd be growing a Mo to support Mens health.

Well, I have to admit that so far I've been weak - I couldn't do it.  So I was growing a beard with the idea of trimming it back at some stage.  Anyways tonight I was sitting down doing some coding:

 

Coding away...

 

When suddenly horse spoke up.... Neeeiiiiiggghhhh.  It startled me!

 

Wha?

 

Anyway, horse reminded me of my promise and told me that I really must grow my Mo.

 

Hey horse... you've got a point there!

 

I agreed, and the very next minute I was in the bathroom giving myself a good old trim

 

The mo!

 

Anyway, if you'd like to sponsor my Mo then please go to http://www.movember.com.au/au/sponsor, enter my Rego number which is 6935 and your credit card details.

The money raised by Movember will be used to change the face of men's health by creating awareness and funding research into prostate cancer and male depression.

posted on 11/13/2006 8:45:08 PM ( 4 Comments )


Research means NOT following the herd

In the '80's I was working as a trading floor operator for a stockbroker.  For most of the '80's stocks went up - and quickly too!  Then, in the late '80's something amazing happened, the stockmarket fell massively in a single day.  Overnight, the fortunes of thousands of people had been dashed.  I remember being on the trading floor that morning with emotion, people, and cameras everywhere.  At one point I looked up into the viewer gallery and I saw an old man crying uncontrollably - an image that will live with me forever.  It was not a good day for a lot of people.

Only a couple of months prior to the stockmarket collapse I was having dinner with my boss and he taught me an important lesson about herd mentality, he said this: 

When your taxi driver starts giving you tips on hte stockmarket, it's time to sell everything you own.

This tip taught me more about the real nature of herd mentality than anything that I'd heard before or ever since.

So move forward 20 years and we've seen some very real examples of herd mentality played out with the IT boom and it's subsequent, spectacular bust and we are now starting to see a similar thing with the general mindset relating to climate change and the environment.  When faced with massive and emotive statements about the environment it is better - and probably more profitable - to spend the precious time that you have gathering facts and forming your own opinions about what needs to be done rather than taking what Rupert Murdoch's mignons have to say at face value.  Do a little research.

Let's start with something simple (and topical) like water consumption.  So for example, you might read statements to the effect that lake and water systems are drying up and that this will lead to entire communities and towns without a water supply.  On hearing such a statement you would likely do one of the following things:

1) Find out which cities will run out of water last and move there - although I can guarantee that when you are living in the only city with water that it won't be a pleasant place to be. smile_regular
2) Run around with your hands in the air telling everybody to stop using water.
3) Do some research about use your findings to inform yourself and others about what is really happening.  Then use those facts to inform yourself and others about the truth.
4) Stand on a street corner holding a sign which states that the "End of the world is nigh"

If like me, you believe that option 3 is the most sensible then the next step is to start thinking about how you would get your head around such an important and large problem.  Start logically by breaking the subject down into the many variables that go into making up the problem:

1) How much water can the current local catchment systems hold?
2) How much water could possibly be captured each year by existing catchment systems?
3) How much water can be treated each year?
4) What is the total water consumption per year?
5) What is the average per household consumption of water per year?
6) What is the projected population growth for the next 20 years?

Working out all of these variables would go some way in determining how close (or far) a region is to running out of water.  Once you have the high level pieces of the puzzle worked out then you simply need to find trusted sources of information for the metrics behind each of those. 

Or you could guess smile_regular... go ahead, how much water do you think that the average household uses per day?

posted on 11/13/2006 4:30:54 PM ( 0 Comments )


NPR : New Windows Has New Sound

As Frank pointed out, some of the new Vista sounds have started finding their way on the web.    Just today NPR put up a soundbite which explains the Windows sounds dating back to Windows 95 and also provides us with the new Vista startup sound: 

Link to NPR : New Windows Has New Sound

posted on 11/12/2006 8:54:43 PM ( 1 Comments )


Do you even know what greenhouse gases are?

I've got a few blogs nowadays and this is really the only one that I seem to post into - and that is mostly because of LiveWriter.  LiveWriter makes it so simple to write a blog post - or part of one - and then submit it without even having to visit the website itself.  Anyways, I've gone and signed myself up for another blog over on the new HiTechAndGreen community portal.  This is a new blogging community that was started by Phil Beadle - with some inspiration from Corneliu and myself.

My reasons for wanting to blog on that site are not because I'm a greenie or a hippy - far from it in fact.  Actually I'm constantly amused by the number of people who seem to be jumping on the green bandwagon nowadays.  Last year these gloom-meisters were running around telling us that America's hurricane season was a sign of impending doom.  This year it's Australia's drought.  Or the build up of "stuff" in the sky.  Or some ice melting in Antarctica. 

Worse still, the number of people who regurgitate gloom about the environment is either scary or laughable - I'm not sure which one.  How many times have you heard a colleague sit down and tell you about how much the sea level will rise over the next 50 years?  What about deforestization - ever had to sit through that one?  To be honest I'd really prefer it if most of these people would just shut up and build themselves an Ark or something.

Unlike most of the people who rant about the environment my goals are simple - I really just want to understand how to measure a few things.  For example, we all "consume stuff", but what parts of the consumption are actually bad, and how can I measure that.  Better still, how can I profit from telling others about their own consumption and their part in the economics of life.  For me this is my opportunity to really teach myself a skill that I've long lusted after - research.  Research is a skill that is being diminished by the one-click world of Google and the new media.  People hear something and believe it to be true without even having the faintest clue of how they would ratify such assertions.  It's a dangerous world allright... but not because of "greenhouse gases".

That's enough for now.  I really just wanted to put a post here which mentions that I'll likely be writing a few articles on my HiTechAndGreen blog.  However that probably won't happen on a large scale until that site supports LiveWriter. 

 

Bonus Question:
Thanks for sitting through this rant of mine.  To earn bonus points, please leave a comment citing which is your favourite greenhouse gas - and why. smile_regular

posted on 11/11/2006 9:48:26 PM ( 7 Comments )


Creating a Tabbed View

Part 1 - Creating a Tabbed View
Part 2 - Creating Dynamic Tabs
Part 3 - Dynamic Tabbed Web Part Pages 

Download the code for this article. 


During my podcast interview with Craig I discuss how readers of my book learn how to take the basic components in the portal framework - zones, web parts, etc - and to customize them to suit everyday requirements.  In the book I really strove to show examples that are quite common, and that my readers would undoubtedly be called upon to implement in their own portals.  A couple of these examples were:

  1. A catalog zone which displays in a pop-up dialog.
  2. An editor zone with collapsible/expandible editor parts.
  3. The ability for users to remove web parts that cause a page to crash.

Anyways, today while browsing the ASP.NET forums I saw a request for a common portal feature - tabbed views.  Before I explain how to implement such a feature, take a look at the following 2 images which show tabbed views implemented in the Google and Live portals:

 

Live Portal Pages Google Portal Pages

 

 

Throughout the remainder of this article I will discuss what is required to allow users to have a tabbed view and to add code that allows a user to drag web parts from one tab and onto another tab.  When our page is complete it will look like so:

 

Custom Portal Pages

As you can see, it's from this simple page that a user could drag the Untitled web part from WebPartZone1 (which resides on Tab 1) and onto another zone named WebPartZone2 (which resides on Tab 2).  OK, without further ado, let's get cracking.  First things first, let's create a basic page with some tabs on it...

 

Create a page with Tabs

For our example, we'll create a very simple page with 2 tabs with a zone in each tab.  Each zone will begin with a single web part.  To do this I need to add the following HTML to my web form:

<asp:WebPartManager id="WebPartManager1" runat="server" />

<div id="page">
    <div id="tabs>
        <span class="tabheader" id="tabheader1" onmouseover="DisplayTab(1);">Tab 1</span>
        <span class="tabheader" id="tabheader2" onmouseover="DisplayTab(2);">Tab 2</span>

    </div>
    <div id="tab1" class="tabpage_visible">
        <div class="tabbody">
            <asp:WebPartZone ID="WebPartZone1"runat="server">
            <ZoneTemplate>
                <asp:TextBox ID="TextBox1"runat="server" />
            </ZoneTemplate>
           
</asp:WebPartZoneID>

        </div>
    </div>
    <div id="tab2" class="tabpage_hidden">
        <div class="tabbody">
            <asp:WebPartZone ID="WebPartZone2"runat="server">
            <ZoneTemplate>
                <asp:Calendar ID="Calendar1"runat="server" />
            </ZoneTemplate>
           
</asp:WebPartZoneID>

        </div>
    </div>
</div>

From the HTML we can see that the first control which has been added is the WebPartManager; this control is required on all web part pages as it really is the brains of all of the portal operations.  Next we can see that I've added a DIV element with an ID of "tabs" which will contain the SPAN's for each tab that I want to display.  You could use an HTML UL for the tabs if you want to get a little fancier with the CSS styles but I've used SPAN's for simplicity.  After the tab elements we have DIV's for each page that is associated with a tab.  For example, the DIV with the ID of "tab1" is associated with the SPAN with the ID of "tabheader1".  The idea being that when the user clicks on a tabheader, a piece of javascript will get executed to ensure that the correct tab page is visible.  Before taking a look at the javascript which will handle the clicks on the tab headers, I'll quickly present the CSS that is used to layout the page:

.tabpage_visible {
    height: 300px;
    width: 400px;
    background-color: yellow ;
    display: "";
    position: absolute ;
}

.tabpage_hidden {
    height: 300px;
    width: 400px;
    background-color: yellow ;
    display: none ;
    position: absolute ;
}

.tabheader {
    height: 40px;
    width: 150px;
    background-color: silver ;
    color: black ;
    position: relative ;
}

.tabbody {
    height: 100%;
    background-color: white ;
}

Again, we have some very simple stuff happening here.  The tabpages have a style for their visible and hidden state; theres a style for the tabs in the header; and finally a style which sets some styles for the body of a tab page.  Very simple stuff.  The magic that will allow a user to switch between tab pages is a small piece of javascript which is invoked when the user clicks on tab - it looks like so:

var tabs = ["tab1", "tab2"] ;
var _currentTab = null ;

window.onload = function() {
    DisplayTab(1) ;
}

function DisplayTab( tabNumber ) {

    var newTab = document.getElementById("tab" + tabNumber) ;
    if( newTab == null || newTab == _currentTab )
        return ;

    for( var i=0; i<tabs.length; i++ ) { var tab = document.getElementById(tabs[i]) ;
        tab.className = (tab == newTab) ? "tabpage_visible" : "tabpage_hidden" ;
    }
    _currentTab = newTab ;
}

Two global variables - tabs and _currentTab - are used to store references to the tabs and to keep track of which tab is the one that is currently being displayed to the user.  When window loads, we preset the currently loaded tab to be tab1; this is achieved by calling our DisplayTab helper function and passing in the number of the tab that we want to display.  This is the same helper function which gets called when the user clicks on a tab link.

So that's the end of our simple tabbed page and at this point you can run it and click between the tab pages. 

 

Enabling dragging between tabs

Now that we've seen how to create a very simple tabbed interface we need to work out how to allow the user to drag web parts between separate tabs.  The way that we'll be doing that in this article is by listening to drag events and then writing some custom logic to determine whether the drag is occurring over one of our pages.  To do this we'll attach an event handler to the ondragover event of the document using the attachEvent method - also we must remember to clean up after ourselves by calling detachEvent when the page unloads:

window.onload = function() {
    DisplayTab(1) ;
    document.body.attachEvent("ondragover", CheckTabs);
}

document.onunload = function() {
    document.body.detachEvent("ondragover", CheckTabs);
}

Here we see that the attach/detach event methods have been added to the code which will handle the page loading and unloading.  Now whenever the user is dragging web parts around on their page, the method that we've wired up to the ondragover event of the document will be run - the CheckTabs method which looks like so:

function CheckTabs() {
    var eventLocation = __wpGetPageEventLocation(window.event, true);
   
    for( var i=0; i<tabs.length; i++ ) {
        var tab = document.getElementById(tabs[i]) ;

var headerId = "tabheader" + (i+1) ;
        var tabHeader = document.getElementById(headerId) ;
        if (IntersectsWith(eventLocation, tabHeader)) {
            DisplayTab( i+1 ) ;
            break ;
        }
    }
}


function IntersectsWith(location, el) {
    var withinX = (location.x < (el.offsetLeft + el.offsetWidth)) && (location.x > el.offsetLeft)
    var withinY = (location.y < (el.offsetTop + el.offsetHeight)) && (location.y > el.offsetTop)
    return withinY && withinX ;
}

The first thing that you'll notice about the CheckTabs function is that it calls a helper function named __wpGetPageEventLocation to determine the location of the dragover event which has just taken place.  The wpGetPageEventLocation function is a private function that is contained within the resources of the ASP.NET .dll and probably isn't really designed to be called from your own code smile_regular  It doesn't really do anything overly special and so you could just include your own logic for getting the location of the event - but I'm going to use their here for brevity.

As we progress down through the CheckTabs method you will see that what we are doing is to cycle through each of the tabs and using another custom function named IntersectsWith to check whether the event location (the drag) is over a tab - if so, we call our handy DisplayTab function to display that tab.

That's really all there is to being able to drag web parts between pages and at this point you should run your page to note that when you drag a web part from one zone, and drag it up over a tab, that the tab page becomes the active page and you will be able to view the other zone.

Gotcha!

For those of you who have made it this far and run the example, you will notice that while you can drag a web part and have it switch pages, you are not actually able to drop that web part into the zone on the other page.  When I first created this sample today and I saw this behavior I was stumped - in fact it took me a couple of hours to debug the issue.  It turns out that positioning logic on the previously hidden zone is a little screwy and that, whenever we switch between tab pages we must call another private ASP.NET javascript function to make things right smile_omg.  So, provided you are happy enough calling a couple of undocumented ASP.NET javascript functions I will now show you which function to call smile_regular:

function DisplayTab( tabNumber ) {

    var newTab = document.getElementById("tab" + tabNumber) ;
    if( newTab == null || newTab == _currentTab )
        return ;

    for( var i=0; i<tabs.length; i++ ) {

var tab = document.getElementById(tabs[i]) ;
        tab.className = (tab == newTab) ? "tabpage_visible" : "tabpage_hidden" ;
    }
    _currentTab = newTab ;
    __wpm.UpdatePositions() ;
}

The function in question is highlighted in red and has been inserted at the end of the DisplayTab helper function.  This function cycles through the zones contained within the web part manager and ensures that the left, right, top, and bottom measurements are correctly reflected in the in-memory instances of all zone and web part variables. 

That's it, re-run your page now and you should have a perfectly working prototype that allows you to drag web parts from one tab page to another.

Now that you've read this article, you should read part 2 where we will look at how to make the tabs dynamic.

Read Part 2 >>

 

posted on 11/11/2006 5:34:41 PM ( 37 Comments )


Have you met Ms. Dewey?

I was reading this post on Amy's blog today about a cool search service called Ms. Dewey.  What a lot of fun! smile_regular

posted on 11/10/2006 6:49:04 AM ( 0 Comments )


Podcast with Craig Shoemaker on Web Parts

This morning I had a podcast interview with Craig Shoemaker on his Polymorphic Podcast where we discussed web parts and the portal framework:

Link to Craig Shoemaker : Podcasting (Web) Parts

 

The podcast will hopefully go up sometime around the new year so I will blog again when it does.  I was very grateful for the opportunity to discuss the portal framework in such detail because I'm sure that it's still a widely misunderstood and underutilized piece of the application development puzzle.

Craig's podcast is a unique format and I've been listening to it for a while - in fact it's the only technical podcast that I listen to regularly.  The style of Craig's podcast is extremely conversational and the speakers have always been excellent.  Craig's recent interviews with Miguel (creating extensible architectures) and Rob Howard were especially enjoyable.

posted on 11/9/2006 12:09:58 PM ( 0 Comments )


Free Windows Vista Icons

I got this link from Duncan's blog this morning:

Link to .: VistaICO.com :. FREE Windows Vista Icons - Best Desktop Icons for Windows

This site offers 82 large sized png icons for Vista.  Looks good!

posted on 11/9/2006 7:03:04 AM ( 1 Comments )


CLR Inside Out: Investigating Memory Issues -- MSDN Magazine, November 2006

I just finished reading this excellent article about how to debug memory issues in .NET: 

    Link to CLR Inside Out: Investigating Memory Issues -- MSDN Magazine, November 2006

 

Highly recommended!

posted on 11/8/2006 10:59:07 AM ( 1 Comments )


What Great .NET Developers Ought To Know

I'm always looking for the link to this great resource:

Link to Scott Hanselman's Computer Zen - What Great .NET Developers Ought To Know (More .NET Interview Questions)

 

As of today I'm internalizing that resource as an official member of the Readify hiring process smile_regular  Thanks Scott!

posted on 11/1/2006 5:17:10 PM ( 0 Comments )