Fast Blur (Box Blur with accumulator)

This post is similar to my previous post, but this post is about blurring an existing image, the previous post was about rendering colored rectangles.

For a game I’m creating (check out a beta at Flow) I needed a really fast way to repeatedly blur images (WriteableBitmap in this case) in Silverlight.
There are blur functions as image effects, and if that satisfies your needs then you should go with that. But I needed to generate my bitmap, blur it, update it, blur it and so on.

I’ve submitted the code below to the WriteableBitmapEx project as a contribution, but it hasn’t been accepted nor rejected yet. I’m publishing it here in case anyone needs it.

Box Blur is a very fast method for blurring (http://www.vcskicks.com/box-blur.php) but for it to be fast you must implement it as an accumulator, not a convolution loop.

Finding implementations of Box Blur, in C#, that uses convolution kernels (as in the link above) is trivial, finding one that uses an accumulator proved more difficult. The method below uses an accumulator.

The code for using the blur method looks like this;


WriteableBitmap bitmap = new WriteableBitmap((BitmapSource)Image.Source);
bitmap.BoxBlur(13);
Image.Source = bitmap;
bitmap.Invalidate();

Before Box Blur;

After Box Blur (range=13);

Running BoxBlur on this 512×512 takes about 32 ms (averaged over 1000 runs) on my computer.

public static void BoxBlur(this WriteableBitmap bmp, int range)
{
	if ((range & 1) == 0)
	{
		throw new InvalidOperationException("Range must be odd!");
	}

	bmp.BoxBlurHorizontal(range);
	bmp.BoxBlurVertical(range);
}

public static void BoxBlurHorizontal(this WriteableBitmap bmp, int range)
{
	int[] pixels = bmp.Pixels;
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int halfRange = range / 2;
	int index = 0;
	int[] newColors = new int[w];

	for (int y = 0; y < h; y++)
	{
		int hits = 0;
		int r = 0;
		int g = 0;
		int b = 0;
		for (int x = -halfRange; x < w; x++)
		{
			int oldPixel = x - halfRange - 1;
			if (oldPixel >= 0)
			{
				int col = pixels[index + oldPixel];
				if (col != 0)
				{
					r -= ((byte)(col >> 16));
					g -= ((byte)(col >> 8 ));
					b -= ((byte)col);
				}
				hits--;
			}

			int newPixel = x + halfRange;
			if (newPixel < w)
			{
				int col = pixels[index + newPixel];
				if (col != 0)
				{
					r += ((byte)(col >> 16));
					g += ((byte)(col >> 8 ));
					b += ((byte)col);
				}
				hits++;
			}

			if (x >= 0)
			{
				int color =
					(255 << 24)
					| ((byte)(r / hits) << 16)
					| ((byte)(g / hits) << 8 )
					| ((byte)(b / hits));

				newColors[x] = color;
			}
		}

		for (int x = 0; x < w; x++)
		{
			pixels[index + x] = newColors[x];
		}

		index += w;
	}
}

public static void BoxBlurVertical(this WriteableBitmap bmp, int range)
{
	int[] pixels = bmp.Pixels;
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int halfRange = range / 2;

	int[] newColors = new int[h];
	int oldPixelOffset = -(halfRange + 1) * w;
	int newPixelOffset = (halfRange) * w;

	for (int x = 0; x < w; x++)
	{
		int hits = 0;
		int r = 0;
		int g = 0;
		int b = 0;
		int index = -halfRange * w + x;
		for (int y = -halfRange; y < h; y++)
		{
			int oldPixel = y - halfRange - 1;
			if (oldPixel >= 0)
			{
				int col = pixels[index + oldPixelOffset];
				if (col != 0)
				{
					r -= ((byte)(col >> 16));
					g -= ((byte)(col >> 8 ));
					b -= ((byte)col);
				}
				hits--;
			}

			int newPixel = y + halfRange;
			if (newPixel < h)
			{
				int col = pixels[index + newPixelOffset];
				if (col != 0)
				{
					r += ((byte)(col >> 16));
					g += ((byte)(col >> 8 ));
					b += ((byte)col);
				}
				hits++;
			}

			if (y >= 0)
			{
				int color =
					(255 << 24)
					| ((byte)(r / hits) << 16)
					| ((byte)(g / hits) << 8 )
					| ((byte)(b / hits));

				newColors[y] = color;
			}

			index += w;
		}

		for (int y = 0; y < h; y++)
		{
			pixels[y * w + x] = newColors[y];
		}
	}
}
public static void BoxBlur(this WriteableBitmap bmp, int range) { if ((range & 1) == 0) { throw new InvalidOperationException(“Range must be odd!”); }   bmp.BoxBlurHorizontal(range); bmp.BoxBlurVertical(range); } public static void BoxBlurHorizontal(this WriteableBitmap bmp, int range) { int[] pixels = bmp.Pixels; int w = bmp.PixelWidth; int h = bmp.PixelHeight; int halfRange = range / 2; int index = 0; int[] newColors = new int[w]; for (int y = 0; y < h; y++) { int hits = 0; int r = 0; int g = 0; int b = 0; for (int x = -halfRange; x < w; x++) { int oldPixel = x – halfRange – 1; if (oldPixel >= 0) { int col = pixels[index + oldPixel]; if (col != 0) { r -= ((byte)(col >> 16)); g -= ((byte)(col >> 8)); b -= ((byte)col); } hits–; } int newPixel = x + halfRange; if (newPixel < w) { int col = pixels[index + newPixel]; if (col != 0) { r += ((byte)(col >> 16)); g += ((byte)(col >> 8)); b += ((byte)col); } hits++; } if (x >= 0) { int color = (255 << 24) | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8) | ((byte)(b / hits)); newColors[x] = color; } } for (int x = 0; x < w; x++) { pixels[index + x] = newColors[x]; } index += w; } } public static void BoxBlurVertical(this WriteableBitmap bmp, int range) { int[] pixels = bmp.Pixels; int w = bmp.PixelWidth; int h = bmp.PixelHeight; int halfRange = range / 2; int[] newColors = new int[h]; int oldPixelOffset = -(halfRange + 1) * w; int newPixelOffset = (halfRange) * w; for (int x = 0; x < w; x++) { int hits = 0; int r = 0; int g = 0; int b = 0; int index = -halfRange * w + x; for (int y = -halfRange; y < h; y++) { int oldPixel = y – halfRange – 1; if (oldPixel >= 0) { int col = pixels[index + oldPixelOffset]; if (col != 0) { r -= ((byte)(col >> 16)); g -= ((byte)(col >> 8)); b -= ((byte)col); } hits–; } int newPixel = y + halfRange; if (newPixel < h) { int col = pixels[index + newPixelOffset]; if (col != 0) { r += ((byte)(col >> 16)); g += ((byte)(col >> 8)); b += ((byte)col); } hits++; } if (y >= 0) { int color = (255 << 24) | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8) | ((byte)(b / hits)); newColors[y] = color; } index += w; } for (int y = 0; y < h; y++) { pixels[y * w + x] = newColors[y]; } } }

Colored/Shaded Rectangle on a WriteableBitmap

I recently needed a way to render a colored rectangle on a WriteableBitmap in Silverlight – though the code could be used in WPF with minor changes. Typically, you’d not use WriteableBitmaps but different Shapes in WPF, but this time I needed to create my own bitmap.

I’ve submitted the code as a contribution to the WriteableBitmapEx.codeplex.com project, but it hasn’t been accepted nor rejected yet, so I figured I’d post it here in case anyone ever needs something similar.

Drawing a 255×255 shaded block takes 2.06 ms (averaged over 1000 draws).

Shaded rectangle rendered on picture of lena;

WriteableBitmap bitmap = new WriteableBitmap((BitmapSource)Image.Source);
int width = 255;
int start = (512 - width) / 2;
bitmap.DrawFilledRectangle(
 start, start,
 start + width, start + width,
 Colors.White,
 Colors.Red,
 Colors.Green,
 Colors.Blue);

Image.Source = bitmap;
bitmap.Invalidate();

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color)
{
	// Add one to use mul and cheap bit shift for multiplicaltion
	var a = color.A + 1;
	var col = (color.A << 24)
			 | ((byte)((color.R * a) >> 8 ) << 16)
			 | ((byte)((color.G * a) >> 8 ) << 8 )
			 | ((byte)((color.B * a) >> 8 ));

	bmp.DrawFilledRectangle(x1, y1, x2, y2, col);
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color00, Color color01, Color color10, Color color11)
{
	// Add one to use mul and cheap bit shift for multiplicaltion
	var a00 = color00.A + 1;
	var col00 = (color00.A << 24)
			 | ((byte)((color00.R * a00) >> 8 ) << 16)
			 | ((byte)((color00.G * a00) >> 8 ) << 8 )
			 | ((byte)((color00.B * a00) >> 8 ));

	var a01 = color01.A + 1;
	var col01 = (color01.A << 24)
			 | ((byte)((color01.R * a01) >> 8 ) << 16)
			 | ((byte)((color01.G * a01) >> 8 ) << 8 )
			 | ((byte)((color01.B * a01) >> 8 ));

	var a10 = color10.A + 1;
	var col10 = (color10.A << 24)
			 | ((byte)((color10.R * a10) >> 8 ) << 16)
			 | ((byte)((color10.G * a10) >> 8 ) << 8 )
			 | ((byte)((color10.B * a10) >> 8 ));

	var a11 = color11.A + 1;
	var col11 = (color11.A << 24)
			 | ((byte)((color11.R * a11) >> 8 ) << 16)
			 | ((byte)((color11.G * a11) >> 8 ) << 8 )
			 | ((byte)((color11.B * a11) >> 8 ));

	bmp.DrawFilledRectangle(x1, y1, x2, y2, col00, col01, col10, col11);
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color)
{
	// Use refs for faster access (really important!) speeds up a lot!
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int[] pixels = bmp.Pixels;

	// Check boundaries
	if (x1 < 0) { x1 = 0; }
	if (y1 < 0) { y1 = 0; }
	if (x2 < 0) { x2 = 0; }
	if (y2 < 0) { y2 = 0; }
	if (x1 >= w) { x1 = w - 1; }
	if (y1 >= h) { y1 = h - 1; }
	if (x2 >= w) { x2 = w - 1; }
	if (y2 >= h) { y2 = h - 1; }

	int i = y1 * w;
	for (int y = y1; y < y2; y++)
	{
		int i2 = i + x1;
		while (i2 < i + x2)
		{
			pixels[i2++] = color;
		}
		i += w;
	}
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color00, int color01, int color10, int color11)
{
	// Use refs for faster access (really important!) speeds up a lot!
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int[] pixels = bmp.Pixels;

	// Check boundaries
	if (x1 < 0) { x1 = 0; }
	if (y1 < 0) { y1 = 0; }
	if (x2 < 0) { x2 = 0; }
	if (y2 < 0) { y2 = 0; }
	if (x1 >= w) { x1 = w - 1; }
	if (y1 >= h) { y1 = h - 1; }
	if (x2 >= w) { x2 = w - 1; }
	if (y2 >= h) { y2 = h - 1; }

	// Retrieve the color channels
	byte a00 = (byte)(color00 >> 24); byte r00 = (byte)(color00 >> 16); byte g00 = (byte)(color00 >> 8 ); byte b00 = (byte)(color00);
	byte a10 = (byte)(color10 >> 24); byte r10 = (byte)(color10 >> 16); byte g10 = (byte)(color10 >> 8 ); byte b10 = (byte)(color10);
	byte a01 = (byte)(color01 >> 24); byte r01 = (byte)(color01 >> 16); byte g01 = (byte)(color01 >> 8 ); byte b01 = (byte)(color01);
	byte a11 = (byte)(color11 >> 24); byte r11 = (byte)(color11 >> 16); byte g11 = (byte)(color11 >> 8 ); byte b11 = (byte)(color11);

	//r01, r10
	int xrange = x2 - x1;
	int yrange = y2 - y1;

	for (int x = 0; x < xrange; x++)
	{
		int negx = xrange - x;
		byte atop = (byte)((a00 * negx + a01 * x) / xrange);
		byte rtop = (byte)((r00 * negx + r01 * x) / xrange);
		byte gtop = (byte)((g00 * negx + g01 * x) / xrange);
		byte btop = (byte)((b00 * negx + b01 * x) / xrange);

		byte abottom = (byte)((a10 * negx + a11 * x) / xrange);
		byte rbottom = (byte)((r10 * negx + r11 * x) / xrange);
		byte gbottom = (byte)((g10 * negx + g11 * x) / xrange);
		byte bbottom = (byte)((b10 * negx + b11 * x) / xrange);

		for (int y = 0; y < yrange; y++)
		{
			int negy = yrange - y;
			int p = (y + y1) * w + x + x1;

			int color =
				(byte)((atop * negy + abottom * y) / yrange) << 24 |
				(byte)((rtop * negy + rbottom * y) / yrange) << 16 |
				(byte)((gtop * negy + gbottom * y) / yrange) << 8 |
				(byte)((btop * negy + bbottom * y) / yrange);

			pixels[p] = color;
		}
	}
}

All of a sudden, my Silverlight Application stops working

It’s happened several times, all of a sudden, my Silverlight Business Application stops working! When I hit F5, Mozilla comes up as usual – but the page is blank and there’s no error message – and no application. Sucks.

It happened just now as I re-checked out the entire project from the SVN source. Turns out that to fix it, all I have to do is select a startup page other than the Default.aspx page.

For some unknown reason, Default.aspx has become the startup page for my web application, and for some other unknown reason, that just isn’t good enough.

To correct the issue, I select another startup page (ImageEvolvatron.GuiTestPage.aspx) in the Solution Explorer, right click and select “Set As Start Page” and my application is good to go again.

Pointless, but one of those things you’ve got to learn, I guess;

If your Silverlight web application stops responding, try changing the “Start Page”

Silverlight Business Application – WebContext?

I just created a new Silverlight Business Application from the Visual Studio templates – it compiles fine but wherever “WebContext” is used, the Visual Studio IDE reports;

Cannot resolve symbol ‘WebContext’

The text “WebContext” is colored in red and intellisense doesn’t work on it, but it does work on “WebContext.Current”, which is even stranger. Dear IDE, make up your mind!

Anyways, it compiles! What gives!?

Technorati-taggar: ,,

Silverlight pages that require login, part 3

This page is part 3 in a series of pages about “Silverlight pages that require login”. The parts are part 1, part 2 and part 3.

I’m evaluating using Silverlight and RIA services to create a web based application. Right now I’d like to set something like this up;

  1. Some links – secured links – cannot be clicked unless you’re logged in – part 1
  2. If the user logs in, the secured links should automatically be enabled – part 1
  3. If the user logs out, the secured links should automatically be disabled – part 1
  4. If the user logs out while accessing a page that requires authentication, the user should be booted off the page – part 2
  5. If anyone directly accesses a page that requires authentication, the user shouldn’t see any information on the page – all information on the page is to be considered sensitive. part 2
  6. If the user is logged off while on the on the page, then the user should be booted off the page – part 2
  7. If the user isn’t logged in, the user should be asked to log in and if the user fails to log in, he should be booted to the main page. This is similar to 5 but 5 is about prohibiting access, this is about allowing login then access and the prohibition is a fallback – part 3

I could plug the check into the page itself, in the OnNavigatedTo event, but I want to use the navigation framework. The Frame event Navigated is too late, that’s after the navigation has taken place. If only there was a way to inject handling before the actual navigation has taken place… Well, there seems to be just such an event, Navigated. Lets give that a try, in our main page, add the following event handler and navigate to it;

            &lt;navigation:Frame
                x:Name=&quot;ContentFrame&quot;
                Style=&quot;{StaticResource ContentFrameStyle}&quot;
                Source=&quot;/Home&quot;
                Navigated=&quot;ContentFrame_Navigated&quot;
                Navigating=&quot;ContentFrame_Navigating&quot;
                NavigationFailed=&quot;ContentFrame_NavigationFailed&quot;&gt;
                &lt;navigation:Frame.UriMapper&gt;
                    &lt;uriMapper:UriMapper&gt;
                        &lt;uriMapper:UriMapping Uri=&quot;&quot; MappedUri=&quot;/Views/Home.xaml&quot;/&gt;
                        &lt;uriMapper:UriMapping Uri=&quot;/{pageName}&quot; MappedUri=&quot;/Views/{pageName}.xaml&quot;/&gt;
                    &lt;/uriMapper:UriMapper&gt;
                &lt;/navigation:Frame.UriMapper&gt;
            &lt;/navigation:Frame&gt;

Initially, we’ll simply try to trap the navigation attempt and kill it dead – if the user isn’t logged in. Note how we use the name of the page as a string and not a constant or some other nicer method. This is clearly bad, and will turn ugly if more than one secured page is used. Therefore it’s I might look for a better solution further on.

Anyway, here’s the code that cancels forbidden navigation attempts, or at least that looks like its doing the job;

        private void ContentFrame_Navigating(object sender, NavigatingCancelEventArgs e)
        {
            if (e.Uri.Equals(&quot;/DemoPage&quot;))
            {
                if (WebContext.Current.User.IsAuthenticated == false)
                {
                    e.Cancel = true;
                }
            }
        }

About the only Uri property that I can access is the OriginalString, because the Uri is so seriously broken. This leaves us with a huge problem, because program will stop the user accessing the secured page using this url;

http://localhost:58921/Myapp.ApplicationTestPage.aspx#/DemoPage

But this one will be let right through;

http://localhost:58921/Myapp.ApplicationTestPage.aspx#/DemoPage#bob

Where “bob” will be passed as a parameter string to the backing service. This is bad, because that makes circumventing our security a breeze! Luckily, in part 2 I added a fallback that raises an exception, but still, bad show!

And this one also fails, because equals is case sensitive, but the page-mapping code isn’t case sensitive;

http://localhost:58921/Myapp.ApplicationTestPage.aspx#/DemoPAge

So what to do? What I’d like to do is ask the navigation framework what page-class it intends to use to fullfill the navigation, and then prevent users from accessing secured pages. I would have liked the NavigatingCancelEventArgs event to have that information – but alas. Anyway, it turns out that our Frame.UriMapper contains a method called MapUri. This method takes the incoming Uri and performs the internal mapping with the different translations that have been set up.

Using strings have these disadvantages;
I decided to use create an application that

1) Disables certain links when you’re logged off
2) Asks you to login when trying to access those pages through deep linking

I succeeded – it wasn’t even very difficult, nice works guys! You can read about my attempts here; https://lotsacode.wordpress.com/2010/02/21/silverlight-pages-that-require-login-part-1/

Unfortunately, that only takes us half way, we’re still stuck with case-differences and the fact that arguments are padded to the actual path.

However; the method I use to verify which pages are ok to visit leaves me dissatisfied. I’d like to be able to ask the navigation framework which frame-class it intends to use, not what the name of the .xaml file is! Using the name of the xaml file these caveats;

  1. It will break as soon as I refactor the name of the class/xaml
  2. It forces me to compare strings, and string comparison is case sensitive in c#, but the navigation framework isn’t. So that leaves a big risk, locked down pages may be visited by changing the casing in the query. I’ve seen this bug in actual forum answers.
  3. It’s just plain ugly.

Comparing types is sooo much nicer. If I could get the type, I could inherit from something like <code>SecuredPage</code> – and automatically resctrict access to all pages that inherit from that class.

The closest I can come at this point is to check the path for the presence of my xaml file name, in a non-case sensitive manner. Note that I’m including the initial slash and the .xaml token – this is to prevent false positives;

        public bool CaseInsensitiveContains(Uri uri, string value)
        {
            string fullString = uri.ToString().ToLower(CultureInfo.InvariantCulture);
            value = value.ToLower(CultureInfo.InvariantCulture);
            return fullString.Contains(value);
        }

        private void ContentFrame_Navigating(object sender, NavigatingCancelEventArgs e)
        {
            Uri mappedUri = ContentFrame.UriMapper.MapUri(e.Uri);
            if (CaseInsensitiveContains(mappedUri, "/DemoPage.xaml"))
            {
                if (WebContext.Current.User.IsAuthenticated == false)
                {
                    e.Cancel = true;
                }
            }
        }

Now with that horror out of the way, let’s look at how we can ask the user to login.

If a login is required, the login window should be opened. And once that’s closed and the the login was a success, then the user should be navigated to the desired page. Otherwise, the page should navigate to the home page. From what I can tell, there are no events in the login form that we can hook into, so I’m adding my own event.

I’m adding this code to to the class LoginRegistrationWindow

        public event EventHandler<EventArgs> Closed;

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            if (Closed!=null)
            {
                Closed(this, e);
            }
        }

And I’m adding code to show the login if the page is restricted. The navigation code in the MainPage looks like this;

        private void LoginOrGoToMain(Uri uri)
        {
            if (WebContext.Current.User.IsAuthenticated == false)
            {
                LoginRegistrationWindow loginRegistrationWindow = new LoginRegistrationWindow();
                loginRegistrationWindow.Closed +=
                    (s, e) =>
                        {
                            if(WebContext.Current.User.IsAuthenticated)
                            {
                                // Try again!
                                ContentFrame.Navigate(new Uri(uri.ToString(), UriKind.Relative));
                            }
                        };
                loginRegistrationWindow.Show();
            }
        }

        private void ContentFrame_Navigating(object sender, NavigatingCancelEventArgs e)
        {
            Uri mappedUri = ContentFrame.UriMapper.MapUri(e.Uri);
            if (CaseInsensitiveContains(mappedUri, "/DemoPage.xaml"))
            {
                if (WebContext.Current.User.IsAuthenticated == false)
                {
                    e.Cancel = true;
                    LoginOrGoToMain(e.Uri);
                }
            }
        }

Which works so good that I’m tempted to remove the disabling of the hyperlinks that started us off in part 1…

Silverlight pages that require login, part 2

This page is part 2 in a series of pages about “Silverlight pages that require login”. The parts are part 1, part 2 and part 3.

I’m evaluating using Silverlight and RIA services to create a web based application. Right now I’d like to set something like this up;

  1. Some links – secured links – cannot be clicked unless you’re logged in – part 1
  2. If the user logs in, the secured links should automatically be enabled – part 1
  3. If the user logs out, the secured links should automatically be disabled – part 1
  4. If the user logs out while accessing a page that requires authentication, the user should be booted off the page – part 2
  5. If anyone directly accesses a page that requires authentication, the user shouldn’t see any information on the page – all information on the page is to be considered sensitive. part 2
  6. If the user is logged off while on the on the page, then the user should be booted off the page – part 2
  7. If the user isn’t logged in, the user should be asked to log in and if that fails, he should be booted to the main page. This is similar to 5 but 5 is about prohibiting access, this is about allowing login then access and the prohibition is a fallback – part 3

At this point, I have a link that’s disabled if I’m logged out and enabled if I’m logged in. But with Silverlight 3.0/RIA Services, I can copy a link (an HTML link, as it were) and paste that into a browser, and I’ll access the page directly. Thus, it doesn’t matter if the link is enabled or not!

The link to my demo page looks like this (you’ll notice I’m on the rather famous localhost server!);
http://localhost:56897/Myapp.ApplicationTestPage.aspx#/DemoPage

First off, I add an exception to my demo page, so that it’s impossible to view the page even if you somehow are able to stumble on to it;

    public partial class DemoPage : Page
    {
        public DemoPage()
        {
            // Fail as early as possible!
            if (WebContext.Current.User.IsAuthenticated == false)
            {
                throw new InvalidOperationException(&quot;You must be logged on to view this page!&quot;);
            }
            InitializeComponent();
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }

If I try to access the page directly, I get a huge exception! Clearly not a good way of restricting access, but if someone somehow got through our secured perimeter, that’s better than the alternative.

If I log on before I directly access the page, then the page shows as expected. So far so good. But if I log off, I’m still left on the page! Time to boot the user when he logs out.

What we’ll want to do is to again hook up an event to the WebContext.Current.Authentication object to navigate away from the page when the user is logged off;

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            WebContext.Current.Authentication.LoggedOut += Authentication_LoggedOut;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Must unregister the event
            WebContext.Current.Authentication.LoggedOut -= Authentication_LoggedOut;
        }

        private void Authentication_LoggedOut(object sender, System.Windows.Ria.ApplicationServices.AuthenticationEventArgs e)
        {
            // Navigate to the home page! But how?
        }

As you can see from the comment in Authentication_LoggedOut we need a method for navigating to the main page – canceling any pending changes and hiding any currently visible information. But how?

After a bit of googling, it would seem that the MainPage is the holder of the Frame that in turn is showing the current page - the page that we want to navigate away from. And in my demo project, it's called ContentFrame - here's the xaml;

        &lt;Border x:Name=&quot;ContentBorder&quot; Style=&quot;{StaticResource ContentBorderStyle}&quot;&gt;
            &lt;navigation:Frame
                x:Name=&quot;ContentFrame&quot;
                Style=&quot;{StaticResource ContentFrameStyle}&quot;
                Source=&quot;/Home&quot;
                Navigated=&quot;ContentFrame_Navigated&quot;
                NavigationFailed=&quot;ContentFrame_NavigationFailed&quot;&gt;
                &lt;navigation:Frame.UriMapper&gt;
                    &lt;uriMapper:UriMapper&gt;
                        &lt;uriMapper:UriMapping Uri=&quot;&quot; MappedUri=&quot;/Views/Home.xaml&quot;/&gt;
                        &lt;uriMapper:UriMapping Uri=&quot;/{pageName}&quot; MappedUri=&quot;/Views/{pageName}.xaml&quot;/&gt;
                    &lt;/uriMapper:UriMapper&gt;
                &lt;/navigation:Frame.UriMapper&gt;
            &lt;/navigation:Frame&gt;
        &lt;/Border&gt;

At this page about Silverlight 3 Navigation Framework (and this webcast) we’re told that from the page, we can use the Page.NavigationService to find the Frame that navigated to this page. And that frame has a Navigate method, so we’ll try that;

        private void Authentication_LoggedOut(object sender, System.Windows.Ria.ApplicationServices.AuthenticationEventArgs e)
        {
            NavigationService.Navigate(new Uri(&quot;/Home&quot;, UriKind.Relative));
        }

And that worked a charm! If the user logs out – he’s redirected to the main page. Without any message specifying what has happened – which would probably be nice.

Now, I’d like the user to be asked to log in, instead of simply being refused access to the page. I’ve added that to part 3.

Silverlight pages that Require login, part 1

This page is part 1 in a series of pages about “Silverlight pages that require login”. The parts are part 1, part 2 and part 3.

I’m evaluating using Silverlight and RIA services to create a web based application. Right now I’d like to set something like this up;

  1. Some links – secured links – cannot be clicked unless you’re logged in – part 1
  2. If the user logs in, the secured links should automatically be enabled – part 1
  3. If the user logs out, the secured links should automatically be disabled – part 1
  4. If the user logs out while accessing a page that requires authentication, the user should be booted off the page – part 2
  5. If anyone directly accesses a page that requires authentication, the user shouldn’t see any information on the page – all information on the page is to be considered sensitive. part 2
  6. If the user is logged off while on the on the page, then the user should be booted off the page – part 2
  7. If the user isn’t logged in, the user should be asked to log in and if that fails, he should be booted to the main page. This is similar to 5 but 5 is about prohibiting access, this is about allowing login then access and the prohibition is a fallback – part 3

This blog post will outline my struggles as I try to make this happen.

First, I added a link that eventually will required authentication/that the user is logged in. Initially, it’s enabled even when the user isn’t logged in;

Then I added a property that the link can bind to, to determine if the user is authenticated or not;

        public bool IsAuthenticated
        {
            get
            {
                return WebContext.Current.User.IsAuthenticated;
            }
        }

I also have to set the datacontext to “this” to allow the xaml to bind to the backing properties;

        public MainPage()
        {
            InitializeComponent();
            this.DataContext = this;
            this.loginContainer.Child = new LoginStatus();
        }

Next I bound the IsEnabled property of the link to my new property;

 <HyperlinkButton
 x:Name="Link3"
 Style="{StaticResource LinkStyle}"
 NavigateUri="/DemoPage"
 TargetName="ContentFrame"
 Content="demo (requires login)"
 IsEnabled="{Binding Path=IsAuthenticated}"/>

Now the link is disabled when I start the application;

But it’s not enabled when I login! That’s because I need to add an event that refreshes the property whenever the user logs in or logs out. That requires a digression where we make the main page implement INotifyPropertyChanged so that I could create a bindable property that handles change notification;

    public partial class MainPage : UserControl,  INotifyPropertyChanged
    {
         public event PropertyChangedEventHandler PropertyChanged;

Then I added this code to allow me to use “type safe” methods with INotifyPropertyChanged;

        public event PropertyChangedEventHandler PropertyChanged;

 protected static string GetPropertyName<T>(Expression<Func<T>> action)
 {
 var expression = (MemberExpression)action.Body;
 return expression.Member.Name;
 }

 protected virtual void SendPropertyChanged<T>(Expression<Func<T>> action)
 {
 string propertyName = GetPropertyName(action);
 SendPropertyChanged(propertyName);
 }

 private void SendPropertyChanged(string propertyName)
 {
 if (PropertyChanged != null)
 {
 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
 }
 }

Back on track, we’re now ready to send notifications whenever a the user logins in our out. A bit of research shows that WebContext.Current.Authentication is responsible for this. So hooking that up as shown below makes the link enable/disable appropriately(notice the wonderful use of lambda instead of delegates, good or bad? You decide);

        public MainPage()
        {
WebContext.Current.Authentication.LoggedIn +=
 (sender, e) => SendPropertyChanged(() => IsAuthenticated);
 WebContext.Current.Authentication.LoggedOut +=
 (sender, e) => SendPropertyChanged(() => IsAuthenticated);

            InitializeComponent();
            this.DataContext = this;
            this.loginContainer.Child = new LoginStatus();
        }

Here’s a shot when the user’s logged out and the link is disabled;

Next I’ll make the page refuse users that are logged out – or at least force them to log in. Check out part 2 that describes how to do that.