Scott Hanselman

Introducing Workspace Reloader - A Visual Studio AddIn to save your open files across project reloads

May 02, 2012 Comment on this post [27] Posted in Open Source | VS2010
Sponsored By

Works on my machineA while back my buddy Sam Saffron (from Stack Overflow and Mini Profiler) complained to me on Skype that he was finding it very irritating that every time he updated his project outside of Visual Studio he would be prompted to "Reload Project" and would lose all his open files because Visual Studio would close them.

This apparently is becoming kind of an issue at Stack Overflow. Since they use distributed source control and often have a dozen or more folks all coding inside the same project they are integrating all the time. They'll be deep into something, update their project to test it and all their open windows close.

It's a weird Visual Studio behavior that I've never understood. Visual Studio saves all your open files and window positions when you close the IDE and restores them when you open your solution. But when you open a project then right click and "Unload Project" you'll lose all your windows. I've reported it as a bug and it's also been voted up at User Voice, visited as a Question at StackOverflow, and a few folks have tweeted about it (The SO guys with their thumbs on the scale, no doubt) and been bugging some folks but then I got the idea to just fix it myself. It'd be a good chance to write my first Visual Studio Add-In, see if this is even possible, and fix an irritant at the same time.

DOWNLOAD: Workspace Reloader Visual Studio Add-in - "This package will reload the code files you had open when your project file was modified and unloaded then reloaded"

Warranty: To be clear this is the smallest of extensions. It only listens to two events and it's only 12k so you have no reason that I know of to be afraid of it. Plus, it works on my machine so you've got that going for you.

Creating a Visual Studio Extension

Developing Visual Studio Extensions requires some patience. It's gotten a lot better with Visual Studio 2010 but back in the 2003-2005 days it was really hairy. There's a number of different kinds of things you can extend. You can add menus, add tool bars, commands, new templates, new kinds of designers and visualizers, as well as use just the shell to create your own IDE.

I wanted to create an add-in with Zero UI. I had no need for buttons or menus, I just wanted to listen to events and act on them. I downloaded the Visual Studio 2010 SDK after reading this blog on extending Visual Studio 2010. Make sure you get the right version. I have Visual Studio 2010 SP1 so I needed the updated Visual Studio 2010 SP1 SDK.

File | New Project | Visual Studio Package

I made a new Visual Studio Package. This builds into a VSIX (which is just a ZIP file - isn't everything?). A VSIX has a manifest (which his just XML - isn't everything?) that you can edit in a GUI or as a text file.

I want my VSIX package to work on Visual Studio 11 Beta as well as Visual Studio 2010  so I added to the SupportedProducts node like this. VSIXs other than templates aren't supported in Express (I keep pushing, though):

<SupportedProducts>
<VisualStudio Version="10.0">
<Edition>Ultimate</Edition>
<Edition>Premium</Edition>
<Edition>Pro</Edition>
</VisualStudio>
<VisualStudio Version="11.0">
<Edition>Ultimate</Edition>
<Edition>Premium</Edition>
<Edition>Pro</Edition>
</VisualStudio>
</SupportedProducts>

I also setup the name, version and description in this file. 

I need to decide when my package is going to get loaded. You can add one or more ProvideAutoLoad attributes to a Package class from the VSConstants class. A number of blogs posts say you need to hard code a GUID like this, but they are mistaken. There are constants available.

[ProvideAutoLoad("{ADFC4E64-0397-11D1-9F4E-00A0C911004F}")]

I can have my package automatically load in situations like these:

  • NoSolution   
  • SolutionExists
  • SolutionHasMultipleProjects   
  • SolutionHasSingleProject
  • SolutionBuilding
  • SolutionExistsAndNotBuildingAndNotDebugging
  • SolutionOrProjectUpgrading
  • FullScreenMode

For my package, I need it loaded whenever a "Solution Exists," so I'll use this Constant (in lieu of a hard coded GUID):

[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)]

Next, I wanted to listen to events from the Solution like the unloading and loading of Projects. I started with the IVsSolutionsEvents interface that includes OnBefore, OnAfter and OnQuery for basically everything. Elisha has a simple listener wrapper as an answer on StackOverflow that I modified.

The SolutionEventsListener uses the very useful Package.GetGlobalService to get hold of the solution.

IVsSolution solution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution;
if (solution != null)
{
solution.AdviseSolutionEvents(this, out solutionEventsCookie);
}

We then sign up to hear about things that might happen to the Solution using the IVsSolutionEvents interfaces and making them look like friendly events.

public event Action OnAfterOpenProject;
public event Action OnQueryUnloadProject;

int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
{
OnAfterOpenProject();
return VSConstants.S_OK;
}

int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
{
OnQueryUnloadProject();
return VSConstants.S_OK;
}

I want to hear about things just before Unload happens and then act on them After projects Open. I'll save the Document Windows. There's an interface that manages Documents and Windows for the Shell called, confusingly enough IVsUIShellDocumentWindowMgr

I save the windows just before the unload and reopen them just after the project opens. Unfortunately these are COM interfaces so I had to pass in not an IStream but an OLE.IStream so while the ReopenDocumentWindows is easy below...

listener.OnQueryUnloadProject += () =>
{
comStream = SaveDocumentWindowPositions(winmgr);
};
listener.OnAfterOpenProject += () => {
int hr = winmgr.ReopenDocumentWindows(comStream);
comStream = null;
};

The SaveDocumentWindowPositions is more complex, but basically "make a memory stream, save the documents, and seek back to the beginning of the stream."

private IStream SaveDocumentWindowPositions(IVsUIShellDocumentWindowMgr windowsMgr)
{
if (windowsMgr == null)
{
return null;
}
IStream stream;
NativeMethods.CreateStreamOnHGlobal(IntPtr.Zero, true, out stream);
if (stream == null)
{
return null;
}
int hr = windowsMgr.SaveDocumentWindowPositions(0, stream);
if (hr != VSConstants.S_OK)
{
return null;
}

// Move to the beginning of the stream with all this COM fake number crap
LARGE_INTEGER l = new LARGE_INTEGER();
ULARGE_INTEGER[] ul = new ULARGE_INTEGER[1];
ul[0] = new ULARGE_INTEGER();
l.QuadPart = 0;
//Seek to the beginning of the stream
stream.Seek(l, 0, ul);
return stream;
}

If this does it's job you'll never know it's there. You can test it by installing Workspace Reloader, opening a project and opening a few code files. Now, edit the CSProj as a text file (maybe add a space somewhere) and save it. Visual Studio should prompt you to Reload the Project. Workspace Reloader should keep your files and windows open.

I hope this helps a few people. The source is here.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Back to Basics: Moving beyond for, if and switch

April 26, 2012 Comment on this post [72] Posted in Back to Basics
Sponsored By

I visit a lot of customers and look at a lot of code. I also worked with a number of large production code bases in my previous jobs and I see a lot of ifs, fors and switches. I see loops inside of loops with ifs inside them, all doing various transformations of data from one form to another. I see strings getting parsed to pull bits of data out in ways that are easy to say in English but take 100 lines to say in code.

Should they? When we are just getting started programming we learn about if first, then for, then the much abused switch statement.

I saw this little snippet on Miguel's blog a few weeks ago:

var biggerThan10 = new List;
for (int i = 0; i < array.Length; i++){
if (array [i] > 10)
biggerThan10.Add (array[i]);
}

It's straightforward. Take an array of ints and make a new list with those that are larger than 10. We've all see code like this a million times. Here's the same thing in a few other languages.

C#

var a = from x in array where x > 10 select x; 
var b = array.Where(x => x > 10);

Ruby

a = array.select{|x| x >10}

JavaScript

a = array.filter(function(x){return x > 10});

I'd much rather write these one line operations than the loop and if above. I still see this out in the world, so perhaps people haven't seen enough examples. I asked friends on Twitter to submit their examples. Thank you Twitter friends!

Here's a few nice examples. Iron Shay has some nice LINQ examples on his blog. Please do share yours in the comments. Be sure to use <pre> tags.

NOTE: This is NOT about "shoving stuff into one line" but rather looking at solutions that are equally as readable but also simpler, terser, and less error prone than loops of loops.


def calculate_primes(n):
no_primes = []
primes = []

for i in range(2, 8):
for j in range(i*2, n, i):
no_primes.append(j)

for x in range(2, n):
if x not in no_primes:
primes.append(x)

return primes


calculate_primes(500)


# Can be like this instead!

(lambda n: [x for x in range(2, n) if x not in [j for i in range(2, 8) for j in range(i*2, n, i)]])(500)

From Aaron Bassett


foreach (var i in categories) {
foreach (var x in GetAllChildCategories(i.Id)) {
yield return x;
}
}

//Can be...

return categories.SelectMany(i => this.GetAllChildCategoriesIds(i.Id));

From James Hull


var inputNumbersInString = Console.ReadLine();
var inputNumbersStringArray = inputNumbersInString.Split(' ');
var inputNumbers = new List<int>();

for (int i = 0; i < inputNumbersStringArray.Length; ++i) {
inputNumbers.Add(int.Parse(inputNumbersStringArray[i]));
}

int maxNumber = inputNumbers[0];

for (int i = 1; i < inputNumbers.Count; ++i)
if (inputNumbers[i] > maxNumber)
maxNumber = inputNumbers[i];

Console.WriteLine(maxNumber);

//Or rather...

Console.WriteLine(Console.ReadLine().Split(' ').Select(t => int.Parse(t)).ToList().Max());

From Amit Saraswat


// create a poker deck as a list of two characters strings: 
// rank, suite

char[] figures = "23456789TJQKA".ToCharArray();
char[] suites = "SHDC".ToCharArray();
List<string> deck = new List<string>();

foreach (var figure in figures) {
foreach (var suite in suites) {
deck.Add(string.Format("{0}{1}", figure, suite));
}
}

//Or, neatly
var cards = from r in "23456789TJQKA" from s in "SHDC" select "" + r + s;

From Jack Nova


bool include = false;
if (op == Operator.And) {
bool current = true;
foreach (var item in Items) {
current = current & item.Process();
}
include = current;
}
else {
bool current = false;
foreach (var item in Items) {
current = current | item.Process();
}
include = current;
}
return include;

//Or this lovely Aggregate

return op == Operator.And ?
Items.Aggregate(true, (current, item) => current & item.Process()) :
Items.Aggregate(false, (current, item) => current | item.Process());

From Kevin Meiresonne


sbyte[] sByteArray = new sbyte[100];
byte[] uByteArray = new byte[sByteArray.Length];

for (int i = 0; i < sByteArray.Length; i++) {
uByteArray[i] = (byte)sByteArray[i];
}

//Or, instead of the loop above
byte[] uByteArray1 = Array.ConvertAll(sByteArray, x => (byte)x);

From Fahad Mustafa


Scott: I have to say here that I prefer the first option. ;)

// This is the "classic" solution to the FizzBuzz problem.
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
Console.WriteLine("FizzBuzz");
}
else if (i % 3 == 0) {
Console.WriteLine("Fizz");
}
else if (i % 5 == 0) {
Console.WriteLine("Buzz");
}
else {
Console.WriteLine(i.ToString());
}
}

// One line
Enumerable.Range(1, 100).ToList().ForEach(n => Console.WriteLine((n % 3 == 0) ? (n % 5 == 0) ? "FizzBuzz" : "Fizz" : (n % 5 == 0) ? "Buzz" : n.ToString()));

From Craig Phillips


A good one...I'm surprised more people don't use this.

var temp = String.Empty;
foreach (var entry in myStringList) {
    if (String.IsNullOrEmpty(temp)) {
        temp = entry;
    }
    else {
        entry += ", " + entry;
    }
}

//becomes

var temp = String.Join(", ", myStringList)

From Holger Adam


A class with properties in one line of F#. That'd be a dozen or more lines of C#.

type Person = { Name:string; Age:int }

From Phillip Trelford


/// Input is a string with numbers : 10+20+30+40
/// Output is integer with required sum (100)
string input = "10+20+30+40";
var result = Regex.Split(input, @"\D+").Select(t => int.Parse(t)).Sum();
Console.WriteLine("Result is {0}" ,result);

From Srinivas Iyengar


There are a million things available to the programmer beyond the first three keywords we learn. What are your favorite patterns (doesn't matter what language) that have helped you break away from the basics and move to the next level?


Sponsor: Big thanks to the folks at DevExpress for sponsoring this week's feed. Check out a free trial of CodeRush, one of my favorite products! Introducing CodeRush by DevExpress. The Visual Studio add-in that helps you create more reliable applications. Tools to build & maintain your code without getting in the way of your IDE.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

A world of pretty cloud drive icons - SkyDrive, Google Drive, Dropbox, BitBucket and GitHub

April 24, 2012 Comment on this post [16] Posted in Musings
Sponsored By

Today Google Drive and Windows SkyDrive came out with clients for Windows and Mac. There's also SkyDrive apps for Windows Phone, iPhone, or iPad and OneNote apps that sync to SkyDrive for Windows Phone, Android,iPhone, or iPad.

I'm a paying DropBox customer myself with over 60 gigs in there. I also use BitBucket and GitHub for source code.

I also like tidy and pretty icons, for folders, programs and external drives. I made custom icons for the Visual Studio Command prompt as well as Visual Studio in PowerShell.

I put all these new cloud folders as well as my GitHub and BitBucket folders (these aren't custom apps, just folders where I keep my source repositories) in my favorites in Windows Explorer.

I made custom .ICO icons for GitHub and BitBucket from high-res PNGs. Just right click on a Folder, click Properties, then Shortcut Change Icon to select your custom icon.

Pretty Icons for all my Cloud Services

Select your icon from your folder properties as shown in this screenshot:

Checking a folder's icon

That DropBox icon isn't fitting in with my whole "Cloud Folder" aesthetic. I was going to make a custom DropBox icon by combining their icon along with the standard Windows Explorer folder icon but I double-checked the Dropbox.exe first. You never know if the designer may have left some optional or alternative views of an icon in the EXE. Plus we know that the DropBox folks pay attention to details.

I can see in %APPDATA%\Dropbox\bin\Dropbox.exe that there are other views of the main DropBox icon.

Ah, there are hidden DropBox icons!

Ah, that's much nicer!

Changing the DropBox icon to a folder

I put my custom icons up on SkyDrive.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Create a great mobile experience for your website today. Please.

April 24, 2012 Comment on this post [32] Posted in ASP.NET | HTML5 | Mobile
Sponsored By

People are fascinating with making mobile web sites. It's amazing that we're not impressed with the fact we carry tiny supercomputers in our pockets but we're amazed when a website looks decent on our phones.

There's a few directions you can go when going mobile for your site, and the key is finding balance. You can:

  • Do nothing. Your site will probably work on a mobile device but each day it will look worse and worse to a discerning public with increasing expectations.
  • Use Adaptive/Responsive Design. This is my favorite option. If your site is read-mostly (rather than a data-entry application) you can get a great experience on all devices by adaptively rendering your site based on screen-size. If you're focused on performance you can add a server-side component and resize image for mobile as well. Visit http://mediaqueri.es for inspiration.
  • Use a mobile framework. There's lots great frameworks like Sencha, Kendo, jQuery Mobile and others. These frameworks can get you near-native looking applications using HTML5 techniques.
  • Write a native app. For the time-being while it's cool to try to get native experiences using non-native tools, it's hard. The best native experience on a mobile device will remain a native-built application. This requires the most work with arguably the best experience. However, you CAN get 90-95% of the experience with less than 90% of the effort if you use some of these other techniques. Plus, you'll anger fewer users by not forcing them to download a crappy mobile app by just making a lovely mobile website.

image

If you take a moment and visit my site (this site) on your phone, or just resize the browser to a smaller size, you'll see that this blog is using a "responsive design" by designer Jeremy Kratz. The blog will change it's look based on if it's on a large monitor, an iPad or medium tablet, or a narrow phone. Watch the navigation bar turn into a drop down as the browser gets really narrow, for example.

My site's responsive design, as featured on the MediaQueri.es site

This was a relatively small - although thoughtful - change that instantly made my blog more accessible to the 8% of people who visit my site from a mobile device.

For larger data-focused sites, or sites that are "almost applications" you will want to consider a custom mobile version of your site. This is often done with the help of a mobile framework as mentioned above. I'll use jQuery Mobile as an example here. Let's say I have a conference browser application that looks like this on the desktop. I can navigate by date, speaker, tag, as well as view session details.

My site looks lousy on an iPhone

If I look at this same page on a mobile browser or something like the Electric Plum Mobile Simulator, it looks like crap.

Electric Mobile Simulator

I could use a mobile custom stylesheet just for phones, or I could use a CSS3 media query to make my existing stylesheet more mobile friendly...for example:

@media only screen and (max-width: 1024px) and (max-height: 768px)
{
/* do something, hide something, move something */
}

Or I could use a mobile framework along with a display mode in ASP.NET MVC to render a different view while still using the same controller logic. For example, I could have a _Layout.cshtml (that's like a "master page") and then a _Layout.Mobile.cshtml for mobile devices.

A Views folder with optional *.mobile.cshtml files for each mobile view

Mobile is just a included "display mode." You can create your own however you like. Here's one for Windows Phone. You could theoretically have ones like "tablet" or "nokia." I think you should have as few as you can get away with. Try to avoid complexity. This is just an example.

DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("WP7") {
ContextCondition = ctx => ctx.GetOverriddenUserAgent().Contains("Windows Phone OS")
});

That "WP7" string is what you put in place of * in filename.*.cshtml. So that's _Layout.WP7.cshtml, or Index.WP7.cshtml, etc. For my example I'll just make a _Layout.Mobile.cshtml that will automatically be used when most mobile browsers like Mobile Safari, Blackberry or Windows Phone hit my new site.

Here is a new _Layout.Mobile.cshtml as a starting point for my conference browser mobile site. Remember that you can just File | New Project in Visual Studio with ASP.NET MVC 4 and select Mobile Site to get started on your own.

<!DOCTYPE html> 
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="@Url.Content("~/Content/jquery.mobile-1.0.min.css")" />
<link rel="stylesheet" href="@Url.Content("~/Content/Site.Mobile.css")" />
<script type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")"></script>
<script type="text/javascript">
$(document).bind("mobileinit", function() {
// jQuery Mobile's Ajax navigation does not work in all cases (e.g.,
// when navigating from a mobile to a non-mobile page), especially when going back, hence disabling it.
$.mobile.ajaxEnabled = false;
});
</script>
<script type="text/javascript" src="@Url.Content("~/Scripts/jquery.mobile-1.0.min.js")"></script>
</head>
<body>

<div data-role="page" data-theme="a">
@Html.Partial("_ViewSwitcher")

<div data-role="header">
<h1>@ViewBag.Title</h1>
</div>

<div data-role="content">
@RenderSection("featured", false)
@RenderBody()
</div>

</div>
</body>
</html>

Now that I have a custom _Layout.mobile.cshtml for mobile, THIS file will be used when I hit the site on a mobile device rather than the main _Layout.cshtml.

OK, here my application is using the mobile layout, but the existing session HTML which looks, again, like crap. I'm using a mobile layout with a desktop view.

Electric Mobile Simulator Sessions

The desktop view for a session uses a table (and that's OK you tableless-CSS people because it's a table of information):

<table>
<thead>
<tr><th>Title</th><th>Speaker(s)</th><th>Date</th><th>Room</th><th>Tags</th></tr>
</thead>
<tbody>
@foreach(var session in Model) {
<tr>
<td>@Html.ActionLink(session.Title, "Session", new { session.Code })</td>
<td>@Html.Partial("_SpeakersLinks", session)</td>
<td>@session.DateText</td>
<td>@session.Room</td>
<td>@Html.Partial("_TagsLinks", session)</td>
</tr>
}
</tbody>
</table>

But I need a cleaner mobile layout that respects a smaller screen size. I'll copy my SessionsTable.cshtml and make a SessionsTable.Mobile.cshtml with contents like this:

@using ConferenceSessionsBrowserMvc4.Models
@model IEnumerable<Session>

<h2>@ViewBag.Title</h2>

<ul data-role="listview">
@foreach(var session in Model) {
<li>
<a href="@Url.Action("Session", new { session.Code })">
<h3>@session.Title</h3>
<p><strong>@string.Join(", ", session.Speakers)</strong></p>
<p>@session.DateText</p>
</a>
</li>
}
</ul>

There are a few things to note in this HTML. First, I like that it's not littered with CSS that describes the look and feel of the site, but rather it uses the data- attributes from HTML5 to express the "role" of an element. The UL uses data-role="listview" that tells me it's a listview but doesn't dictate what it looks like.

Within the UL I've got some LIs that use standard semantic tags like A, H3, and P along with STRONG and along with the default theme it looks nice on mobile.

A nice mobile view using jQuery Mobile

ASIDE: See the the "Displaying mobile view" link at the top of the image there? With ASP.NET MVC 4 you can make a View Switcher easily with a partial View like this:

@if (Request.Browser.IsMobileDevice && Request.HttpMethod == "GET")
{
<div class="view-switcher ui-bar-a">
@if (ViewContext.HttpContext.GetOverriddenBrowser().IsMobileDevice)
{
@: Displaying mobile view
@Html.ActionLink("Desktop view", "SwitchView", "ViewSwitcher", new { mobile = false, returnUrl = Request.Url.PathAndQuery }, new { rel = "external" })
}
else
{
@: Displaying desktop view
@Html.ActionLink("Mobile view", "SwitchView", "ViewSwitcher", new { mobile = true, returnUrl = Request.Url.PathAndQuery }, new { rel = "external" })
}
</div>
}

And a ViewSwitcherController to change the "overridden" browser when you click the link. This is all in the jQuery.Mobile.MVC NuGet package that we will update for the final release.

public class ViewSwitcherController : Controller
{
public RedirectResult SwitchView(bool mobile, string returnUrl) {
if (Request.Browser.IsMobileDevice == mobile)
HttpContext.ClearOverriddenBrowser();
else
HttpContext.SetOverriddenBrowser(mobile ? BrowserOverride.Mobile : BrowserOverride.Desktop);

return Redirect(returnUrl);
}
}
OK, back to the Dates view. I can apply the same data- jQuery Mobile techniques to other screens, like the list of dates. I've got a data-role="listview" and a data-role="list-divider" as the dates change.
@model IEnumerable<DateTime>

@{
ViewBag.Title = "All dates";
DateTime lastDay = default(DateTime);
}
<ul data-role="listview">
@foreach(var date in Model) {
if (date.Date != lastDay) {
lastDay = date.Date;
<li data-role="list-divider">@date.Date.ToString("ddd, MMM dd")</li>
}
<li>@Html.ActionLink(date.ToString("h:mm tt"), "SessionsByDate", new { date })</li>
}
</ul>

And get a nice result like this:

jQuery mobile applied to a ListView of dates

You can even get cool data filtering "as you type" features for jQuery Mobile list views by using data-filter="true" on a listview.

data-filter=true in jQuery Mobile

Because these templates are all mobile specific they don't affect the way the site looks on the desktop. Also because these are simply new views for existing URLs and Controllers, I don't need write any new business logic.

It is worth reminding you that it won't always be the case that an application will have its controllers and URLs map neatly such that one desktop view = one mobile view. Sometimes you may need to split up a complex single page desktop interaction into multiple mobile views. This conference application ended up with six views for desktop and six for mobile (Index, Dates, tags, Session(Detail), SessionsTable, and Speakers.) It's conceivable if the application included data entry that I would need to break up some views as well as create some custom methods just for mobile, although with some planning around User Experience you can usually keep this to a minimum.

If the default browser sniffing that decides what's mobile and what's not isn't enough for your project, consider using a 3rd party database of mobile devices like the one provided by 51degrees.mobi. Their 51degrees.mobi mobile framework will help your site adapt to support all mobile devices as they include a database of devices as well as their capabilities. They can even compress images and improve low-bandwidth performance.

They have a NuGet package I can install like this:

51degrees.mobile mobile framework for ASP.NET

51Degrees and libraries like it will add new capabilities to the Request.Browser object. These are just a few examples, there's dozens.

Screen Width: <% =Request.Browser.ScreenPixelsWidth %></li>
Screen Height: <% =Request.Browser.ScreenPixelsHeight %></li>
LayoutEngine: <% =Request.Browser["LayoutEngine"] %></li>
AnimationTiming: <% =Request.Browser["AnimationTiming"] %></li>
BlobBuilder: <% =Request.Browser["BlobBuilder"] %></li>
CssBackground: <% =Request.Browser["CssBackground"] %></li>
CssBorderImage: <% =Request.Browser["CssBorderImage"] %></li>
CssCanvas: <% =Request.Browser["CssCanvas"] %></li>
CssColor: <% =Request.Browser["CssColor"] %></li>
CssColumn: <% =Request.Browser["CssColumn"] %></li>
CssFlexbox: <% =Request.Browser["CssFlexbox"] %></li>
CssFont: <% =Request.Browser["CssFont"] %></li>
CssMediaQueries: <% =Request.Browser["CssMediaQueries"] %></li>

You can use this information on the server side to augment these other techniques. For example, if the requesting device supports CssMediaQueries, great, you should use them, but it not, perhaps you need to fall back to another technique. If you know the screen-size on the server and it's below a certain size you can resize the image before you send it.

Thanks to Jon Galloway, Damian Edwards and Erik Porter for their brainstorming and Steve Sanderson for the sample application.


Sponsor: I want to thank my friends at DevExpress for sponsoring this week's feed. Do take a moment and check out a free trial of CodeRush, one of my favorite products!  Introducing CodeRush by DevExpress. The Visual Studio add-in that helps you create more reliable applications. Tools to build & maintain your code without getting in the way of your IDE.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Root Cause Analysis for Toddlers and Medical Eyeball Tweezers

April 20, 2012 Comment on this post [51] Posted in Musings
Sponsored By

Eye picture from BMJThis has been a very stressful week. Our four year old had a piece of metal in his cornea. Twice. That's two different pieces over multiple days in the same eye. In one week. He's great now, no lasting damage and no vision trouble. That's not his eye pictured at right.

He was having trouble sleeping and was complaining about his eye hurting. He's had eyelashes in his eye before so we check it out, didn't see much, and flushed with saline eye drops anyway. He wouldn't fall asleep and kept waking in a start. About 1 in the morning it was clear that he was in some considerable pain and wasn't going to sleep. We looked again with a bright flashlight. Turns out that little kids not only don't like standing still but they don't like staying still with a bright light in their eyeball. We did get a hint of something, right on the surface of the eye next to the pupil. I couldn't get it out with the edge of a tissue so we headed to the emergency room.

The very kind doctor at the ER took a look with a slit lamp and exclaimed: "It's something metal!" She numbed the eye and tried to remove it but quickly decided it was out of her expertise and call the on call ophthalmologist. They woke up the eye surgeon and brought him in to check it out. We found ourselves with a tired toddler and a tired (but kind) eye doctor after 2am trying to get this metal out of his little eye with some kind of special set of medical eyeball tweezers. Again, may I mention that while my son is and was a trooper, no one likes to hear "eyeball" and "tweezers" in the same sentence, especially when combined into one super scary term: "medical eyeball tweezers."

His patience exhausted, my baby fell asleep crying. The doctor said I got all the metal and 80% of the rust.

Rust? Yes, rust. Rust that looks roughly like this.

Rust rings in your eyeball

Iron rusts in the eye very quickly and creates a rust ring (iron oxide). That ring often needs to be removed as well usually with the equivalent of an "eyeball Dremel tool," like this one below.

Eye Dremel picture from @mycastleproject

We were told to return the following day to get the remainder of the rust. We went home, tired but feeling reasonably comfortable that this strange thing was a fluke and that everything would be cool. The following day an attempt was made to get the last bit of rust but bless him, he wouldn't stay still so the we and doctor decided against further trauma. The chances are that the very small bit of rust will just dissipate. If not, we'd deal with it later when he's older.

My son went to school and the next day came home complaining about his eye. The doctor had said it would feel like there was something in his eye (even though it had been removed) and that this was common. However, he couldn't sleep and insisted something was wrong. We have learned to listen to little people, even and especially at 2am.

There was something new in his eye - the same eye.

I could only assume that the doctor didn't get everything the last time. Off to the ER again (don't mess with eyes) but this time they were not wiling to wake up the eye doctor. We saw him a few hours later first thing in the morning. I asked if it was the same piece and he said, "no, it's the same eye but a different location. You can tell because the original rust ring is a marker."

He was shocked to say the least. "In 30 years I've never seen someone get something in their eye twice. Not even in people who grind metal for a living."

He tried to get it out but my baby wasn't having it. The decision was made (and not lightly) to use general anesthesia to perform the eye surgery procedure and get it out. This kind of thing requires one stays completely still and you just can't ask a 4 year old to do that.

I just couldn't get my head around the idea that this was a new piece of metal. What if a third one showed up? What was he doing or what was he around to cause this? Was he banging metal cars together? Was it shavings off his metal bed? Maybe sandbox sand being thrown in the air? Something from our new car?

My wife and I became obsessed with "root causing." I spent a day moving through my son's life, touching everything. Toys, beds, toothbrushes, car seats, furniture. No luck.

We were at the hospital yesterday and he was put under and had the procedure done. The doctor said it was successful and not only did he get th second piece of metal out but also cleaned up the now two rust rings.

We asked again, "How do we keep this from happening again?"

The doctor said, "You've got to find the cause or it very well could reoccur. The thing is..." he reiterated, "I've never seen this, even in metal grinders or folks in manufacturing."

We took baby home with a healthy dose of paranoia. Should he wear glasses until this is figured out? Then we had an idea. Where does a 4 year old come in contact with grinding metal. Why our son and not the other kids?

Wait. Metal grinders. Where does my son go where metal grinds together?

The playground swing. Specifically the tire swing. I've seen him spin on the swing for hours with his head parallel to the ground, eyes wide open looking at the clouds.

I went to the playground, found the swing and touched the metal ball where the hip joint fits into the bearings. My finger came out covered in what looked like glitter. Metal shavings. The tire swing joint was dry and cold - effectively a metal grinder rotating directly over his eyes.

There's nothing more satisfying than The Answer.

Tire Swing photo by Craigie3000. Used under CC.

I spoke to the principal of the school and he made some calls and actually spoke to the designer of the playground product who hooked him up with the designer of the swivel. They are swapping the Tire Swing Hanger for a Heavy Duty hanger that includes a rubber boot to cover the joint.Tire SwivelHeavy Duty Tire Swivel

This was a clear and satisfying end to a very painful experience for the little guy. I'm just happy we figured it out but I think we are going to be paranoid about eyeballs for a the foreseeable future.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.