#LightSwitch and #Syncfusion: simply beautiful applications ($10.000 April raffle!)

With all the blog posts about the new LightSwitch HTML client, it’s easy to lose track of the continued investments in the Silverlight client and the server tier…

One minute summary

Today, this blog post will teach you what you can create by combining 30 minutes of your time with your existing LightSwitch skills, a little ASP.Net Web API creation, some Nuget-for-beginners and custom Silverlight controls to add a dashboard to a LightSwitch application.

Or, because a picture says a thousand words: today we’re going to create this (click-to-enlarge):

LightSwitch & syncfusion: deliver simply beautiful applications

Or, because a sample says more than a thousand pictures: <Download link coming soon> .

Ten minute summary

Prerequisites

To follow this guide, you’ll need:

1. Creating reports on the server

Instead of dragging all records over the wire, we’re going to access the ApplicationServerContext directly on the server, aggregate and transform the data there, then send the summary back.

You’ll know why the latter approach is preferred once you pay for your own Azure bills. :p

Hit the “Toggle View” button in solution explorer so that the LightSwitch application is in File View.  Then, right-click on the server project > Add a folder > Name:”Controllers”.

Next, right-click that new folder and choose to Add New Item… > Web API Controller Class > Name:TopRegionsController.cs  (If you are unfamiliar with ASP.Net Web API, you can skim through this tutorial.)

Before actually implementing the controller, we’ll configure the server for these new controllers.  Right-click the project > Add New Item > Global Application Class:

using System;
using System.Web.Http;
using System.Web.Routing;

namespace LightSwitchApplication
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {

            RouteTable.Routes.MapHttpRoute(
               name: "ReportsApi",
               routeTemplate: "reports/{controller}"
               );

        }
    }
}

Back to the controller, where we’ll implement the GET command:

using System;
using System.Linq;
using System.Web.Http;
using Microsoft.LightSwitch; //1.

namespace LightSwitchApplication
{
    public class TopRegionsController : ApiController
    {
        // GET api/
        public object Get()
        {
            using (ServerApplicationContext context = ServerApplicationContext.CreateContext()) //2.
            {
                var query = context.DataWorkspace.NorthwindData
                    .Orders
                    .Where(o => o.ShipRegion != null)
                    .GroupBy(
                        o => o.ShipRegion) //3.
                    .Select(
                        g => new //4.
                        {
                            Label = g.Key,
                            Value = g.Count()
                        }
                        )
                        .Execute() //5.
                        .OrderByDescending(g => g.Value)
                        .Take(15)
                        .ToList();
                return query;
            }
        }
    }
}

Some code highlights:

  1. Don’t forget to add the using statement to bring the Microsoft.LightSwitch namespace into scope.
  2. This is the powerfull ServerApplicationContext.  An IDisposable  , type-safe object that represents your LightSwitch application on the middle tier.  You can access user information, the Dataworkspace, …
  3. Pro tip! This GroupBy method (only available after step 1.) is something you can’t do over OData.  The grouping itself is done directly in the data source, if your data source supports it.  SQL obviously does.  (In other words, calling this GroupBy method will cause your SQL query to contain a GROUP BY statement :-))
  4. We’re gathering the results in an anonymous type.  Bluntly put: why bother?
  5. Don’t forget to execute the query!

Et voila, the server is done.  One quick way to test if you have done everything correctly, is to press F5 to start debugging, then navigate your browser or fiddler to http://localhost:<assigned port number>/reports/TopRegions .

Image 037

2. Fetching the data from the client

Add an empty Screen to the LightSwitch (Silverlight: in or out-of-browser) application called “DashBoards”, using the “List and Details” screen template but leaving Screen Data blank.

From the Screen Designer, hit the “Write Code” button and choose “DashBoards_Activated”.  This will generate a method stub for you, where you can add some code to match the following outline snippet:

using Microsoft.LightSwitch.Presentation.Extensions;
using System.ComponentModel;
namespace LightSwitchApplication
{
    public partial class Dashboards : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public object TopRegions { get; set; }

        partial void Dashboards_Activated()
        {
            //What comes here? :-s
        }
    }
}

As you can see, we’ve added a local property called “TopRegions”, of type object.  Because this can’t be done from the screen designer, we’ll have to notify when the property changes ourselves too.   The big question is what we should fill in as method body.  How do we find out what the server address is, perform the HTTP GET call asynchronously, and handle exceptions?

Luckily, when there’s a tough technical challenge, you can often hire “a developer in a box” (as I call it), or “Paul Van Bladel in a Nuget package” (as normal people would refer to it).

Open the package-manager console (if you don’t know what that is: View>Other Windows>Package Manager Console), make sure the LightSwitchApplication.Client project is selected as Default Project, then type:

Image 038

Pro tip!: after typing “inst” or “thelight”, you can press tab and have the rest of the command auto-completed.

This package will install some utility extension methods, which we can call from our method body (and effectively reduce this article from 14 pages to just 4):

        partial void Dashboards_Activated()
        {
            this.StartWebApiRequest<MySyncfusionControls.DataItemViewModel[]>//1
                ("reports/TopRegions",//2.
                (exception, result) =>
                {
                    if (exception != null)
                    {
                        this.ShowMessageBox("There was an error while fetching the data.");

                    }
                    else
                    {
                        Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => //3.
                            {
                                TopRegions = result;
                                this.PropertyChanged(this, new PropertyChangedEventArgs("TopRegions"));  
                            }
                        );
                    }
                }
            );
        }

Some code highlights:

  1. StartWebApiRequest is one of the methods added by the Nuget package, doing all the heavy lifting.  Thanks Paul!  We call the method and (by using the generic method signature) ask to cast the return value (a JSON list of anonymously typed stuff) to an array of MySyncfusionControls.DataViewModel (We’ll create this class in a second, by the way).  In a loosely typed language like JavaScript, or in an un-sandboxed environment like WPF, you could get away with not casting the return value (ie: casting it to object) but you’ll run into security problems trying to bind to it from the user controls later.  (Silverlight is very harsh on reflection-lovers, meaning safer for the end-user).
  2. This is the last part of the URI by which the server is exposing it’s endpoint, determined by the routing we set up in the Global.asax file, and the name of the controller.
  3. We’re currently on the logical thread.  This event will be handled on the UI thread.  Read about the incredible dual dispatcher objects in LightSwitch… O… wait…  //TODO: can someone blog about dual dispatcher objects?

 3. Creating the user control

To visualize the report to the user, you need some kick-ass controls.  LightSwitch Controls come in three flavors:

We’ll take the latter route: right-click on the solution > Add New Project > Silverlight 5 Class Library > Name:MySyncfusionControls

Replace the default class1 with:

    public class DataItemViewModel
    {
        public string Label { get; set; }
        public double Value { get; set; }
    }

This is the DTO we’ll use, duly note that the names of the two properties (“Label” and “Value”) match the one used in our anonymous type used to return the data from the server.

Goody, now for the actual control.  Add references to Syncfusion.Chart.Silverlight, then right-click the project > Add New Item > Silverlight User Control > Name:ColumnChartWrapper.  Replace the XAML with:

<UserControl x:Class="MySyncfusionControls.ColumnChartWrapper"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:syncfusion="clr-namespace:Syncfusion.Windows.Chart;assembly=Syncfusion.Chart.Silverlight"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <syncfusion:Chart Margin="10" Name="Chart1" MinHeight="300" MaxHeight="450" MinWidth="600" MaxWidth="1000" Background="White">
            <syncfusion:ChartArea BorderThickness="0">
                <syncfusion:ChartArea.Header>
                    <TextBlock FontSize="20" Text="{Binding DisplayName}" />
                    <!-- 1. -->
                </syncfusion:ChartArea.Header>
                <syncfusion:ChartArea.PrimaryAxis>
                    <syncfusion:ChartAxis RangePadding="Normal" ValueType="String" Interval="1"/>
                </syncfusion:ChartArea.PrimaryAxis>
                <syncfusion:ChartArea.SecondaryAxis>
                    <syncfusion:ChartAxis RangePadding="Normal" IsAutoSetRange="True"/>
                </syncfusion:ChartArea.SecondaryAxis>
                <syncfusion:ChartSeries x:Name="series" 
                    BindingPathX="Label" 
                    BindingPathsY="Value" 
                    DataSource="{Binding Value.TopRegions}" 

                    Type="Column" StrokeThickness="0"
                    ColorEach="True"
                    EnableEffects="True"
                    EnableAnimation="True" AnimateOption="Rotate" AnimateOneByOne="True" AnimationDuration="00:00:10"
                    >
                    <!-- 2. -->
                    <syncfusion:ChartSeries.AdornmentsInfo>
                        <syncfusion:ChartAdornmentInfo x:Name="Adornments_pot" Visible="True" SegmentLabelFormat="0.0"
                                                                   AdornmentsPosition="Top" 
                                                                   HorizontalAlignment="Center" 
                                                                   VerticalAlignment="Bottom" >
                            <syncfusion:ChartAdornmentInfo.LabelTemplate>
                                <DataTemplate>
                                    <Grid>
                                        <TextBlock  TextWrapping="Wrap" Text="{Binding}" FontSize="20" Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Bottom">
                                        </TextBlock>
                                    </Grid>
                                </DataTemplate>
                            </syncfusion:ChartAdornmentInfo.LabelTemplate>
                        </syncfusion:ChartAdornmentInfo>
                    </syncfusion:ChartSeries.AdornmentsInfo>
                </syncfusion:ChartSeries>
            </syncfusion:ChartArea>
        </syncfusion:Chart>
    </Grid>
</UserControl>

Some XAML highlights:

  1. Bind to the DisplayName (which we’ll set in a minute)
  2. Well…
    • DataSource is set to Value.TopRegions.  The datacontext is the ContentItem that we’re about to drag on the screen designer.  This ContentItem has a property “Value”, which we’ll bind to the “Screen” in the screen designer.  This screen has a property called “TopRegions”, which we added in the code earlier.
    • BindingPathX and BindingPathsY are set to “Label” and “Value”, which are the names of the properties on or DTO that we created earlier.  This is where you would run into troubles if you didn’t cast the JSON result to a strongly typed object in a strongly typed language in a sandboxed environment.
    • Animations: you need lots of them and Syncfusion has some truly beautiful animations.  For demos, always include “EnableAnimation=”True” AnimateOption=”Rotate” AnimateOneByOne=”True” AnimationDuration=”00:00:10″”, you only get one shot at making a first impression so make sure there’s lots of shinies to catch your audience’s attention .  Pro tip! For production code, removing animations makes customers happier.

4. Finishing the screen

The heavy lifting is over…  So far, we’ve used ASP.Net Web Api and the LightSwitch ApplicationServerContext to gather and expose custom data reports, we’ve used C# code and a Nuget package to get that data to the client, and we created a custom Silverlight control based on one of the 7 billion (more or less) Syncfusion charting controls to visualize that data.

The glue to bind this all together: open the Dashboards screen in the screen designer, and in the middle area, select the main root (labeled “Columns Layout – Dashboard”) > Click on the Add link > New Custom Control. > Add Reference to the MySyncfusionControls library that we created, then > Select ColumnChartWrapper  > Data: Screen (ie: leave the default) > hit OK.

Image 024

Before finishing, select the user control in the screen designer, then in Properties Panel:

  • Set Display Name to “Top Regions”.  Remember the first of the XAML highlights? We’ll bind to this Display Name from the control. :-)
  • Set Label Position to “None”
  • Set Horizontal Alignment to “Stretch”
  • Set Vertical Alignment to “Stretch”

Also, select the Save button in the screen command bar and in Properties Panel, set Is Visible to false.

Finally, press F5…

Boom!

Image 026

By the way: the purple column seems to be falling, that’s because I intentionally took the screenshot in the middle of the  “Rotate” loading animation.  - Showoff…

Thirty minute summary

There is no thirty minute summary, so rinse, repeat, try out some other charting controls, …  I added two more custom controls in the sample <Download link coming soon>, (don’t forget the prerequisites) which you could already see in action at the top of this blog post!  

If you like what you saw, feel free to leave a comment and automatically enter the Syncfusion Raffle…

O yes…  “Almost forgot”… (wink, wink, nudge, nudge) <Smooth transition> 

The Syncfusion Raffle!

You might think that this blog post is a little biased towards Syncfusion.  I won’t deny that, but in fact, the opposite is also true: Syncfusion is biased towards my blog readers.  Even more so, they are giving away five Enterprise Syncfusion Essential Studio licences worth $1999 each!

Let that sink in a little…  Syncfusion is giving my blog readers TEN THOUSAND DOLLARS of licences!

To enter the raffle:

  1. Before May 1st 2013: send out a tweet containing the #LightSwitch and #Syncfusion hashtag, and a link to this blog post.  For example: “#LightSwitch and #Syncfusion: simply beautiful applications. http://wp.me/p1J0PO-eW ” or “Thousands of dollars worth of #Syncfusion licences thanks to this #LightSwitch blog http://wp.me/p1J0PO-eW” or …
  2. Grab the permalink, and post the link to your tweet as a comment to this blog post (make sure you use a valid email address to comment, I need to be able to contact you if you win!)

One entry per person, normal contest rules apply.  If you don’t have twitter, just post the message on your blog, facebook, … 

The winners will be announced on May 1st 2013.

Best of luck, and don’t forget:

Keep rocking LS!

PS: not fan of all those colors?  Don’t worry, the sample <download link coming soon> shows you how add a combo box so you can change your color schema at runtime from “boring grayscale” to “metro” to “acid tripping”… :-)

Image 039

About these ads

21 thoughts on “#LightSwitch and #Syncfusion: simply beautiful applications ($10.000 April raffle!)

  1. Hi Yan,

    This looks fabulous! Unfortunately though in my case the code breaks down in the Get method of the controller with error ‘Query cannot return non-entity types that contain embedded entities’.

    Any ideas?

    Ian MacPherson

  2. Pingback: Beth Massi - Sharing the goodness

  3. Pingback: Beth Massi的中文博客

  4. Pingback: #LightSwitch and #Syncfusion: simply beautiful applications ($10.000 April raffle!): Winners! | Jan Van der Haegen's blog

  5. Pingback: LightSwitch hacking challenge: fix the NullReferenceException | Jan Van der Haegen's blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s