Scott Hanselman

Learning WPF with BabySmash - Factories, Interfaces, Delegates and Lambdas, oh my!

June 12, 2008 Comment on this post [19] Posted in BabySmash | Windows Client | WPF
Sponsored By

NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.

BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Issue Tracker and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!

BabySmash has a little mini-hierarchy of "Figures" that represent the Shapes on the screen. There is a "FigureGenerator" that is meant to return a random Figure whenever the baby hits a key.

I thought it would be interesting to walk through the several different ways one could solve this problem, depending on what version of the .NET Framework one has available. This isn't an exhaustive list, of course, and I'm VERY interested in your refactorings, Dear Reader, so leave them in the comments inside <pre> tags. Thanks to Scott Cate (and his son) for his help with this post today.

Original Yucky Random Factory

What's the catch? Well, here's one. The "FigureGenerator" looks like this currently. I know it sucks because of all the TODOs. If that isn't enough of a hint for you, the switch statement is your 9th hint. This is actually pretty common WTF code that you've likely seen in the wild. Perhaps you'd even admit to writing something like it yourself.

private static Figure GenerateFigure(string letter)
{
//TODO: Should this be in XAML? Would that make it better?
Brush fill = Utils.GetRandomColoredBrush();
if (letter.Length == 1 && Char.IsLetterOrDigit(letter[0]))
{
return new LetterFigure(fill, letter);
}

int shape = Utils.RandomBetweenTwoNumbers(0, 6);
//TODO: Should I change the height, width and stroke to be relative to the screen size?
//TODO: I think I need a shapefactory?
//TODO: Where can I get REALLY complex shapes like animal vectors or custom pics? Where do I store them?
switch (shape)
{
case 0:
return new SquareFigure(fill);
case 1:
return new CircleFigure(fill);
case 2:
return new TriangleFigure(fill);
case 3:
return new StarFigure(fill);
case 4:
return new HeartFigure(fill);
case 5:
return new TrapezoidFigure(fill);
case 6:
return new RectangleFigure(fill);
}
return null;
}

Why so gross? Well, the goal here is to be an object factory, but to be a random object factory that returns any of a list of Figures. Notice, though, that a Letter is a special kind of Figure depending on what key the baby pressed. It's still a figure, except it's the only one that cares what key was pressed.

What I need is a better Factory to make these Figures, but a "random factory" that is a little easier to extend than a Switch statement.

Random List of Factories with Interfaces - The 1.1 Way

I'm trying to create a RandomFactory that makes concrete instances of random Shapes that drive from an abstract class. Its the randomness that's important, so I need to randomly select from a list of potentials.

On the reflection side of things, I could have created an array of System.Types then randomly picked one, then used Reflection via Activator.CreateInstance to create something concrete. However, Reflection should be a last resort, and this isn't that complex of a pattern.

One oldish, simple solution would be to create an array of FigureFactories like this:

interface IFigureFactory
{
Figure CreateFigure(Brush fill);
}

public class StarFigureFactory : IFigureFactory
{
public Figure CreateFigure(Brush fill)
{
return new StarFigure(fill);
}
}
public class SquareFigureFactory : IFigureFactory
{
public Figure CreateFigure(Brush fill)
{
return new SquareFigure(fill);
}
}

I'd need to make an array of these, then pick one randomly:

IFigureFactory[] figfacts = new IFigureFactory[]
{
new StarFigureFactory(),
new SquareFigureFactory()
//etc...
};
IFigureFactory figfac = Utils.RandomBetweenTwoNumbers(0, figfacts.Length);
Figure f = figfac.CreateFigure(fill);

This works pretty well, but requires all those FigureFactories.

Random List of Factories with Generics - The 2.0 Second Way Attempt

But, if I was using .NET 2.0, I might say, "hey, what about generics?" I could start creating a GenericFigureFactory<T> to try and get rid of all those other custom tiny factories.

public class GenericFigureFactory<T> where T : Figure, new() 
{
public Figure CreateFigure(Brush fill)
{
Figure f = new T(fill);
//Cannot provide arguments when creating instance of T
}
}

However, it's not so clean because even though the system KNOWS that T is of type Figure and that Figure has a constructor that takes a Brush, I can't call that constructor. At this point, I'd need to set properties instead of a constructor with a parameter. Poop. FAIL.

Random Factories with Delegates - The 2.0 Way

Perhaps this is too much work, with the generics and the interfaces. All I really need is a bunch of methods where the signature is "take a Brush, return a Figure." Some kind of delegate that had that signature. ;)

public delegate Figure FigureFactory<Brush, Figure>(Brush x);

So that's 2.0 style delegate that takes a Brush and returns a Factory. Remember that a delegate in this example an exemplar. It's an example of what a method should look like. It's not the method itself, just the meta-method.

I can make a list of these factories, defining the body as I add them. Then, grab a random one and call it.

List<FigureFactory<Brush, Figure>> foo = new List<FigureFactory<Brush, Figure>>();
foo.Add(delegate(Brush x) { return new SquareFigure(x); });
foo.Add(delegate(Brush x) { return new StarFigure(x); });
FigureFactory myFunc = foo[Utils.RandomBetweenTwoNumbers(0, foo.Count-1)];
Figure f = myFunc(fill);

That delegate up there that takes something and returns something could be made generic, like this:

public delegate TResult Func<TParam, TResult>(TParam p);

That's SO useful that it was added in .NET 3.5 as System.Func and it lives in System.Core.dll. If you want this kind of functionality in .NET 2.0, then just define your own bunch of Funcs. I got this tip from Scott Cate. Remember, if you're using .NET 3.5, you don't need these, they already exist.

public delegate void Func<T>();
public delegate TRes Func<TSrc1, TRes>(TSrc1 src1);
public delegate TRes Func<TSrc1, TSrc2, TRes>(TSrc1 src1, TSrc2 src2);
public delegate TRes Func<TSrc1, TSrc2, TSrc3, TRes>(TSrc1 src1, TSrc2 src2, TSrc3 src3);
public delegate TRes Func<TSrc1, TSrc2, TSrc3, TSrc4, TRes>(TSrc1 src1, TSrc2 src2, TSrc3 src3, TSrc4 s

Still, this could be cleaner.

Random Factories with Lambdas - The 3.5 Way

As Eric Lippert says:

"At first glance, lambda methods look like nothing more than a syntactic sugar, a more compact and pleasant syntax for embedding an anonymous method in code."

There are some subtle differences, and if you want to learn more I encourage you to check out Part 1, Part 2, Part 3, Part 4 and Part 5 of his detailed series on just those differences. For what we're doing, all that matters is that lambdas are nicer to look at.

Now, replacing the delegates with lambdas changes the delegate way:

List<FigureFactory<Brush, Figure>> foo = new List<FigureFactory<Brush, Figure>>();
foo.Add(delegate(Brush x) { return new SquareFigure(x); }); //etc...

to

var foo = new List
{
x => new SquareFigure(x), //etc...
}

So the whole random generator cleans up to just this chunk of code, with the list of figures moved out to a private field:

private static readonly List<Func<Brush, Figure>> listOfPotentialFigures = 
new List<Func<Brush, Figure>>
{
x => new SquareFigure(x),
x => new CircleFigure(x),
x => new TriangleFigure(x),
x => new StarFigure(x),
x => new HeartFigure(x),
x => new TrapezoidFigure(x),
x => new RectangleFigure(x)
};


private static Figure GenerateFigure(string letter)
{
var fill = Utils.GetRandomColoredBrush();
if (letter.Length == 1 && Char.IsLetterOrDigit(letter[0]))
return new LetterFigure(fill, letter);
var myFunc = listOfPotentialFigures[
Utils.RandomBetweenTwoNumbers(0, listOfPotentialFigures.Count-1)];
return myFunc(fill);
}

This feels MUCH cleaner than switch statement and it's easy to extend with a single line and it exactly expresses what I intend to do. In the future I may look at using an IOC (Inversion of Control) container to add figures dynamically via plugin or discovery model.

I'm interested in your comments as there's very likely an even cleaner pattern to solve this little problem in your head, waiting to get out.

Technorati Tags: ,,

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

Learning WPF with BabySmash - Pushing things up a level with another set of eyes

June 12, 2008 Comment on this post [6] Posted in BabySmash | Learning .NET | Windows Client | WPF
Sponsored By

NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.

BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Issue Tracker and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!

BabySmash has a little mini-heirarchy of "Figures" that represent the Shapes on the screen, along with a little additional information like the name of the Figure ("square", "circle") as well as an English word for the color. I intend to internationalize it at some point.

Figure has been pretty simple so far and doesn't really do anything:

public abstract class Figure
{
private UIElement shape;
private readonly string name;
private readonly string color;

protected Figure(Brush fill, string name)
{
this.color = Utils.BrushToString(fill);
this.name = name;
}

public UIElement Shape
{
get { return shape; }
protected set { shape = value; }
}

public string Name { get { return name; } }
public string Color { get { return color; } }
}

Derived Shapes are mostly declarative, and very repetitive:

public class SquareFigure : Figure
{
public SquareFigure(Brush fill)
: base(fill, "square")
{
Shape = new Rectangle()
{
Fill = fill,
Height = 380,
Width = 380,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
}

public class StarFigure : Figure
{
public StarFigure(Brush fill)
: base(fill, "star")
{
Shape = new Star()
{
NumberOfPoints = 5,
Height = 400,
Width = 400,
Fill = fill,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
}

Last post, we removed a bunch of the Style related stuff and put it into XAML markup as a shared Style application resource we could use all over. This makes things DRYer (Don't Repeat Yourself) but still something doesn't smell right.

I still have to grab the Style and pass the Fill along into the Shape property, and I do it for EVERY Shape. Meh. It's the same four lines over and over again.

public class SquareFigure : Figure
{
public SquareFigure(Brush fill)
: base(fill, "square")
{
Shape s = new Rectangle();
s.Style = Application.Current.Resources["square"] as Style;
s.Fill = fill;
Shape = s;
}
}

Ripe for refactoring I say. Note the call to base() in the Constructor. You'd be surprised how many people either don't know about base() or who knew and forgot. ;)

Oddly, I was already passing Fill into the constructor, and then passing it up the hierarchy to the abstract base class Figure without thinking. This is very common when you slap code together then finally take a breath and LOOK at it. Ever more common when you have someone who isn't "into" the code just look over your shoulder and say "um, what's THAT?" You really can't overestimate how useful another set of eyes are. I did a quick SharedView with Jason this afternoon and his fresh eyes sped up my refactoring considerably.

public abstract class Figure
{
private readonly string name;
private readonly string color;

protected Figure(Brush fill, string name, Shape s)
{
this.color = Utils.BrushToString(fill);
this.name = name;
this.Shape = s;
s.Fill = fill;
s.Style = Application.Current.Resources[Name] as Style;
}

public UIElement Shape { get; protected set; }

public string Name { get { return name; } }
public string Color { get { return color; } }
}

Here we moved everything that was repeated (shared) up into the base class. The Shape property used the C# 3.0 property syntax that let us remove a field (it's generated now). Notice the use of the protected keyword on the setter.

The only thing that "smells" bad about this for me is the call to Application.Current.Resources. This is the moral equivalent to HttpContext.Current as it's saying "reach out into the heavens that you ought not know about and pull a rabbit out of a hat" or, in this case, a resource out of Application.Resources. However, as far as I can tell, this is a minor sin, and a common one, unless I want to start passing all these bits of information around my hierarchy while trying to obey the Law of Demeter, which I'm arguably already breaking.

Regardless, suddenly my library of Figures becomes much simpler. Of course, adding new ones will be even simpler now. For example:

public class RectangleFigure : Figure
{
public RectangleFigure(Brush fill)
: base(fill, "rectangle", new Rectangle()){}
}

public class CircleFigure : Figure
{
public CircleFigure(Brush fill)
: base(fill, "circle", new Ellipse()){}
}

public class TriangleFigure : Figure
{
public TriangleFigure(Brush fill)
: base(fill, "triangle", new Polygon()){}
}

public class StarFigure : Figure
{
public StarFigure(Brush fill)
: base(fill, "star", new Star()){}
}

In the next post I'll refactor the factory that makes these figures into something that allows me to sleep at night. ;)

Technorati Tags: ,,

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

Learning WPF with BabySmash - Keeping it DRY with XAML Styles

June 12, 2008 Comment on this post [8] Posted in BabySmash | Windows Client | WPF
Sponsored By

 NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.

BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Issue Tracker and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!

BabySmash is full of shapes and stuff and those shapes a similar look. They have the same stroke (outline color) and stroke thickness (outline width) for example.

There are a lot of places in my code where I not only repeat the assignment of these styles.

Shape = Shape = new Path()
{
Data = MakeCharacterGeometry(nameToDisplay),
Fill = fill,
Stroke = Brushes.Black,
StrokeThickness = 5,
Height = 400
};

This kind of object initializer code is copy/pasted all over. It's not DRY. (Don't Repeat Yourself) First I started looking for object oriented ways to solve this issue. I figured I'd put in some base class that would do the work, or make a Utility (gasp!) class to do this tedium.

Ideally I wanted this stuff in one place (hence DRY) and I wanted to be able to apply it to my shapes. Later, I realized I also wanted to occasionally apply these properties to some shapes and not others. At that point, my object-oriented idea started to fall down.

I felt (and still feel) like most of the Shape stuff for BabySmash belongs in the XAML markup, and folks on CodePlex agreed. Sherwin Rice kindly pointed me towards Styles.

He suggested storing these properties in named bundles of styles in the XAML. This gives me the arbitrary flexibility I needed.

<Style x:Key="circle" TargetType="Ellipse">
<Setter Property="Width" Value="400"/>
<Setter Property="Height" Value="400"/>
<Setter Property="StrokeThickness" Value="5"/>
<Setter Property="Stroke" Value="Black"/>
</Style>

However, as I started moving most of my shape's details over into XAML, things started repeating again. I was trading one kind of "markup" (the C# kind) for another. Poop. Well, turns out you can base styles on styles, so I was able to keep it DRY again.

<Style x:Key="BabySmashBaseStyle" TargetType="Shape">
<Setter Property="StrokeThickness" Value="5"/>
<Setter Property="Stroke" Value="Black"/>
</Style>

<Style x:Key="trapezoid" TargetType="Path"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Data" Value="F1 M 257.147,126.953L 543.657,126.953L 640.333,448.287L 160.333,448.287L 257.147,126.953 Z"/>
</Style>

<Style x:Key="star" TargetType="BabySmash:Star"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="NumberOfPoints" Value="5"/>
<Setter Property="Width" Value="400"/>
<Setter Property="Height" Value="400"/>
</Style>

These all live in <Application.Resources> and I can apply them as I like:

Shape s = new Ellipse();
s.Style = Application.Current.Resources[Name] as Style;

I appear to have just touched the surface of Styles, but I'm continuing to dig in. WPF is starting to make sense to me. Just a smidge.

Related Links

Technorati Tags: ,

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

Learning WPF with BabySmash - Speech Synthesis

June 11, 2008 Comment on this post [16] Posted in BabySmash | Windows Client | WPF
Sponsored By

image NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.

BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Issue Tracker and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!

There's been a flood of interesting content coming in around BabySmash, including WPF Expert Karl Shifflett who found the original code so nasty that he rewrote it from scratch! I'll do a whole post analyzing his code and how I can refactor my own.

Before that, I wanted to share one little tidbit that isn't explicit to WPF but rather to the .NET Framework 3.0. Most folks think of .NET 3.0 (myself included) as being WPF (Windows Presentation Foundation), WCF (Windows Communication Foundation) and WF (Windows Workflow). However, there's a bunch of miscellaneous goodness in in .NET 3.0 that I always forget about.

In BabySmash I wanted to have the letters and shapes spoken when they appear on the screen, and lazily, rather than recording the sounds, I thought to myself, "self, why not text to speech?"

I know there's TTS (Text to Speech) stuff in Windows as COM Objects, so I went into Add Reference in Visual Studio, found the component and added it. A .NET wrapper got created that makes the COM object look like .NET and off I went.

Turns out that .NET 3.0 includes System.Speech, an official component that does all this for me. I yanked out the COM stuff and put System.Speech in, and got the added benefit of a Cancel method to stop any current speech. This is particularly helpful for BabySmash because when kids hit the keyboard fast the speech system slowed down as words to say queued up. It couldn't say the words as fast as they were said.

objSpeech = new SpeechSynthesizer();
objSpeech.SpeakAsyncCancelAll();
objSpeech.Rate = -1;
objSpeech.Volume = 100;
objSpeech.SpeakAsync(s);

//REMOVED COM STUFF
//objSpeech.WaitUntilDone(Timeout.Infinite);
//objSpeech.Speak(s, SpeechVoiceSpeakFlags.SVSFlagsAsync);

Additionally, by using the COM Component, I got into trouble where Vista has version 5.3 and XP had version 5.0. This made it difficult for developers using XP to build the program. This goes away when using the .NET assembly.

Hopefully I'll get to do more "refactoring via subtraction" as I dig deeper into .NET 3.x.

Also, thanks to Gina at LifeHacker for her post on BabySmash! The comments are pretty good, but the best interaction was these two comments:

"Wow, 15 years of progress with Windows and this is all we have to show for it? No wonder Windows is teh suckage."

Very supportive! ;) And a response from another random commenter:

"Wow, I've seen people take cheap shots at Windows, but this is the winner! A dad who writes a program for his son suddenly contributing to windows being 'teh suckage' ..."

Bam. Baby! Smash!

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

The Weekly Source Code 28 - iPhone with ASP.NET MVC Edition

June 09, 2008 Comment on this post [12] Posted in ASP.NET | ASP.NET MVC | Source Code
Sponsored By
image I've been getting more and more interested in how folks extend their applications using plugins and things. In my new ongoing quest to read source code to be a better developer, Dear Reader, I present to you twenty-eighth in a infinite number of posts of "The Weekly Source Code."

The iPhone 2.0 was announced today and even though I am trying to come up with a better solution to show it off than Northwind, I was moved when I saw Aaron's "Rock the iPhone with ASP.NET MVC" post. I've had this same post in my "to blog" queue for at least two months, but now he's done it himself and beat us all to it. Kudos to Aaron.

I'm primarily an ASP.NET developer and I browse on mobile devices all the time, and have been doing so for years. I made DasBlog and this website sniff and apply a mobile template almost two years ago. If you visit hanselman.com on a BlackBerry or Windows Mobile or a number of other tiny devices, you'll get the same site with a mobile skin. I'll need to do something for the iPhone as well.

Al Pascual added iPhone "support" to Community Server late last year by redirecting iPhone users to his RSS Feed, giving those users a cleaner experience than they would have gotten ordinarily.

Steve Orr has a good article on iPhone Development pointing out a number of important details like the viewport meta tags that give the iPhone clues on how to scale the page as well as his Advanced iPhone Development article with a smidge more detail (not really advanced).

I was wondering how easy it'd be to make an iPhone application with ASP.NET MVC, and it turns out it's pretty easy with a combination of things. First, the IUI project at Google Code is a series of Javascript and PNG assets to make a basic iPhone apps. It's really quite elegant, what the iui team has done, based on work from Joe Hewitt. Joe has a fine introductory blog post that explains some of the concepts.

You can use Safari for to simulate an iPhone, or Firefox with the User Agent Switcher and some customization.

For example, here's the source for the page pictured above. Notice the one CSS and one JS file that are included.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>iUI Prefs Demo</title>
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<style type="text/css" media="screen">@import "../iui/iui.css";</style>
<script type="application/x-javascript" src="../iui/iui.js"></script>
</head>

<body>
<div class="toolbar">
<h1 id="pageTitle"></h1>
<a id="backButton" class="button" href="#"></a>
</div>

<form id="settings" title="Settings" class="panel" selected="true">
<h2>Playback</h2>
<fieldset>
<div class="row">
<label>Repeat</label>
<div class="toggle" onclick=""><span class="thumb"></span><span class="toggleOn">ON</span><span class="toggleOff">OFF</span></div>
</div>
<div class="row">
<label>Shuffle</label>
<div class="toggle" onclick="" toggled="true"><span class="thumb"></span><span class="toggleOn">ON</span><span class="toggleOff">OFF</span></div>
</div>
</fieldset>

<h2>User</h2>
<fieldset>
<div class="row">
<label>Name</label>
<input type="text" name="userName" value="johnappleseed"/>
</div>
<div class="row">
<label>Password</label>
<input type="password" name="password" value="delicious"/>
</div>
<div class="row">
<label>Confirm</label>
<input type="password" name="password" value="delicious"/>
</div>
</fieldset>
</form>
</body>
</html>

Notice the little toggle switches? They are in a div with class="toggle" and a click event handler gets hooked up to those in Javascript:

addEventListener("click", function(event)
{
var div = findParent(event.target, "div");
if (div && hasClass(div, "toggle"))
{
div.setAttribute("toggled", div.getAttribute("toggled") != "true");
event.preventDefault();
}
}, true);

Based on the toggle state, the switch renders as appropriate:

.toggle {
border: 1px solid #888888;
-webkit-border-radius: 6px;
background: #FFFFFF url(toggle.png) repeat-x;
font-size: 19px;
font-weight: bold;
line-height: 30px;
}

.toggle[toggled="true"] {
border: 1px solid #143fae;
background: #194fdb url(toggleOn.png) repeat-x;
}

The iPhone HTML page above has multiple forms, explicit control over divs - all things that MVC is better suited for than WebForms. Aaron explains in his blog post how he just brings IUI into his content folder, but the trick was that IUI expects HTML fragments to be returned from Ajax calls, not JSON.

Aaron's Views are then Partial Views intended for consumption from built-in Ajax calls by IUI, so the product's list page looks just like this. Note the markup is all alone.

<ul id="products" title="Products">
<% foreach (Product p in ViewData.Model) { %>
<li><%= Html.ActionLink(p.ProductName, "Index", "Products", new { id = p.ProductID }) %></li>
<% } %>
</ul>

Very cool and very easy.

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.