Showing posts with label View Model. Show all posts
Showing posts with label View Model. Show all posts

Friday, December 18, 2009

What I Learned from PDC - Client Technologies

Client Technologies

There are many different client side technologies in the Microsoft ecosystem, and each has evolved to meet niche markets and end user needs, including video game, business apps, reports, and web page browsing. The defining technology of the client is probably how the view is rendered and the device’s ability to interact with that rendering.

View Rendering: Microsoft provides two different solutions for rendering a GUI: the thin client solution is HTML/JavaScript rendered inside a web browser, the rich client solution is XAML, which can be rendered in a web browser via a Silverlight plug-in, or as part of a thick client application using WPF. So XAML is dual purpose with the caveat that the end user must install the Silverlight plug-in (5 MB, 30 second, one time operation, just like Flash). Simple HTML has more range, because it runs in any browser, but when you start adding CSS and JQuery libraries (and other fancy things) you begin to limit yourself to a subset of browsers, IE7,IE8,Firefox,… again if you can control your target, this is not a problem. The Silverlight plug-in is designed to remove browser incompatibilities and create a UI that is “run anywhere” including Mac and Linux.

Talking Points: FT29: Microsoft AJAX Library, jQuery, and Microsoft Visual Studio 2010 Stephen Walther, shows how to build thin HTML clients with a new open source AJAX library, including 40 client controls, Open Source.

View Model: The purpose of a View Model is to shape your domain model to a view rendering technology. You must manage the interaction controls, events, value conversion, input validation, and general state of the GUI controls rendering using this model. In WPF/Silverlight, the View Model provides a site to bind the UI to the domain model. Sometimes perceived as additional work by programmers, the decoupling of the view from the domain model actually simplifies the implementation of the client GUI by providing a site for view logic that is independent of the domain. Some good examples are multi-lingual UI’s, currency conversion, hiding sections based on roles, and changing screen presentations based on task, expertise or device size. This separation also makes the application much more testable using an automated test suite.

Talking Points: Newly added ICommand support was the final step in making the view rendering and the view model truly independent and testable. Some Silverlight talks that discuss View Models are Cl19: Building Line of Business Applications with Microsoft Silverlight 4 and John Papa’s talk Cl22: Advanced Topics for Building Large-Scale Applications with Microsoft Silverlight

Monday, August 31, 2009

M-V-VM Product Configuration

Deb and I have created many solutions that support sales or engineering efforts. Each application is a little different, driven by the unique aspects of the product we are selling/designing. We have built systems to sell cars, to quote multi-million dollar communications infrastructure projects, to design chemical plants and gear boxes.



You do enough of these applications and you start to see a software design pattern. You also realize just how important the role of the subject matter expert is in helping you create a successful application.


Our first Silverlight product configuration solution is a Cookie Designer. With a lifetime of experience eating cookies and a trip to the store to read the packaging, I now consider myself a subject matter expert. You can test drive the program HERE.

The Cookie Designer is an entry in the Summer Silverlight Coding Competition -- please try it and vote for our solution. Community points are an important part of the judging in this contest.

Our cookie product configuration solution is composed of a set of ingredients that can be combined without any mutually exclusive constraints. Anyone for cinnamon oatmeal dark chocolate chunk?

The secret to creating a convincing picture is to have each ingredient on its own separate layer and to make visible the layers that are involved -- enter the M-V-VM pattern, and in this case used as an adapter / translator between the composition of the model and what is shown.


<Canvas x:Name="CookieRoot" Height="400" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Clip="M0,0L400,0 400,400 0,400z" RenderTransformOrigin="0.5,0.5">



<Image Height="381" Width="404" Canvas.Left="-9" Canvas.Top="8" Source="Cookie_Images/Base Cookie.png"/>

<Image x:Name="Cinnamon" Height="382" Width="390" Opacity="0.651" Canvas.Left="6" Canvas.Top="13" Source="Cookie_Images/Cinnamon.png" Visibility="Collapsed">

</Image>

<Image x:Name="PeanutButter" Height="379" Width="385" Opacity="0.478" Canvas.Left="7" Canvas.Top="9" Source="Cookie_Images/Peanut Butter.png" Visibility="Collapsed"/>

<Image x:Name="ReesesPeanutButter" Height="379" Width="385" Opacity="0.478" Canvas.Left="7" Canvas.Top="9" Source="Cookie_Images/Peanut Butter.png" Visibility="Collapsed"/>

<Image x:Name="Cocoa" Height="387" Width="389" Opacity="0.678" Canvas.Left="5" Canvas.Top="5" Source="Cookie_Images/Cocoa.png" Visibility="Collapsed">

</Image>

<Image x:Name="Oatmeal" Height="380" Width="387" Opacity="0.412" Canvas.Left="6" Canvas.Top="7" Source="Cookie_Images/Oatmeal.png" Visibility="Collapsed"/>

<Image x:Name="Peanuts" Height="377" Width="381" Canvas.Left="9" Canvas.Top="10" Source="Cookie_Images/Peanuts.png" Visibility="Collapsed"/>

<Image x:Name="Raisins" Height="373" Width="370" Canvas.Left="15" Canvas.Top="10" Source="Cookie_Images/Raisins.png" Visibility="Collapsed"/>

<Image x:Name="Pecans" Height="313" Width="302" Canvas.Left="56" Canvas.Top="56" Source="Cookie_Images/Pecans.png" Visibility="Collapsed"/>

<Image x:Name="Almonds" Height="286" Width="333" Canvas.Left="14" Canvas.Top="59" Source="Cookie_Images/Almonds.png" Visibility="Collapsed"/>

<Image x:Name="WhiteChocolateChips" Height="351" Width="353" Canvas.Left="18" Canvas.Top="45" Source="Cookie_Images/White Chocolate Chips.png" Visibility="Collapsed"/>

<Image x:Name="SemisweetChocolateChips" Height="400" Width="400" Canvas.Left="0" Canvas.Top="0" Source="Cookie_Images/Dark Chocolate Chips.png" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">

</Image>

<Image x:Name="MilkChocolateChips" Height="351" Width="380" Canvas.Left="7" Canvas.Top="45" Source="Cookie_Images/Milk Chocolate Chips.png" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">

</Image>

<Image x:Name="MacadamiaNuts" Height="377" Width="354" Canvas.Left="38" Canvas.Top="12" Source="Cookie_Images/Macadamia Nuts.png" Visibility="Collapsed"/>

<Image x:Name="DarkChocolateChunks" Height="546" Width="456" Canvas.Left="-27" Canvas.Top="-88" Source="Cookie_Images/Dark Chocolate Chunks.png" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">

</Image>

<Image x:Name="MilkChocolateChunks" Height="546" Width="456" Canvas.Left="-27" Canvas.Top="-88" Source="Cookie_Images/Milk Chocolate Chunks.png" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">

</Image>

<Image x:Name="WhiteChocolateChunks" Height="546" Width="456" Canvas.Left="-27" Canvas.Top="-88" Source="Cookie_Images/White Chocolate Chunks.png" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">

</Image>

<Image x:Name="HersheyMiniKisses" Height="134" Width="134" Canvas.Left="134" Canvas.Top="126" Source="Cookie_Images/Hershey Kiss.png" Visibility="Collapsed"/>

</Canvas>





We were careful to name the XAML elements so they could be controlled through an automated binding statement that is generated when the picture is loaded.


void CookieCanvas_Loaded(object sender, RoutedEventArgs e)
{
foreach (Image oItem in CookieRoot.Children)
{
string sName = oItem.Name;
if (string.IsNullOrEmpty(sName))
continue;
var oBinding = new Binding(sName);
oBinding.Mode = BindingMode.OneWay;
oItem.SetBinding(Button.VisibilityProperty, oBinding);
}
}

With all this binding now in place the final step is the view model.

public class CookieVM : ViewModel

{

public CookieVM(Instance oSource)

: base(oSource)

{

}

public override void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)

{

if (e.NewItems.IsNotNull())

foreach (Component oNote in e.NewItems.OfType<Component>())

NotifyPropertyChange(oNote.ClassName);



if (e.OldItems.IsNotNull())

foreach (Component oNote in e.OldItems.OfType<Component>())

NotifyPropertyChange(oNote.ClassName);

}

public Visibility Cinnamon

{

get { return DoesChildOfClassExist("Cinnamon") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility PeanutButter

{

get { return DoesChildOfClassExist("PeanutButter") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility ReesesPeanutButter

{

get { return DoesChildOfClassExist("ReesesPeanutButter") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Cocoa

{

get { return DoesChildOfClassExist("Cocoa") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Oatmeal

{

get { return DoesChildOfClassExist("Oatmeal") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Peanuts

{

get { return DoesChildOfClassExist("Peanuts") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Raisins

{

get { return DoesChildOfClassExist("Raisins") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility HersheyMiniKisses

{

get { return DoesChildOfClassExist("HersheyMiniKisses") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Pecans

{

get { return DoesChildOfClassExist("Pecans") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility Almonds

{

get { return DoesChildOfClassExist("Almonds") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility DarkChocolateChunks

{

get { return DoesChildOfClassExist("DarkChocolateChunks") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility MilkChocolateChunks

{

get { return DoesChildOfClassExist("MilkChocolateChunks") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility WhiteChocolateChunks

{

get { return DoesChildOfClassExist("WhiteChocolateChunks") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility WhiteChocolateChips

{

get { return DoesChildOfClassExist("WhiteChocolateChips") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility SemisweetChocolateChips

{

get { return DoesChildOfClassExist("SemisweetChocolateChips") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility MilkChocolateChips

{

get { return DoesChildOfClassExist("MilkChocolateChips") ? Visibility.Visible : Visibility.Collapsed; }

}

public Visibility MacadamiaNuts

{

get { return DoesChildOfClassExist("MacadamiaNuts") ? Visibility.Visible : Visibility.Collapsed; }

}
}