Detect if the browser will run your LightSwitch HTML app.

I just got a great tip from Michael Washington (yes, that awesome dude from that awesome website) that I wanted to post while I’m working on a large blog post about threading in LightSwitch (whoops),

If an end-user tries to open a LightSwitch application in a browser that is not supported, they are very likely to get stuck on the loading screen, with a little loading animation leading them to believe that the application is almost ready to rock&roll.  Unfortunately, a lot of browsers will silently swallow the JavaScript exceptions (or just show a minor warning icon with a message that makes no sense to end users anyways, at best), making the user wait in vain until the loading icon stops spinning.

One way to reduce the number of support tickets heading towards the internal IT department, is to prepend the loading of the LightSwitch JavaScript libraries with a check if JQuery mobile is supported.


<script type="text/javascript">
$(document).ready(function () {
var supported = $.mobile.gradeA();
if (!supported) {
$(".ui-icon-loading").hide();
$(".ui-bottom-load").append('<div class="msls-header">This browser is not supported. Please upgrade to a more recent, <a href="http://jquerymobile.com/gbs/">supported</a&gt; version.</div>');
} else {
msls._run()
.then(null, function failure(error) {
alert(error);
});
}
});
</script>

Small caveat: not all browsers that support JQuery mobile at A-grade, will be able to run LightSwitch HTML apps.  My WP7.8 for example is not running LightSwitch HTML apps correctly, although it will slip through the net of this check.  This means you can either deal with that small percentage by buying enough hardware to run every possible browser and manually cross-check every LightSwitch feature so that you can keep a completely bullet-proof browsers<>version matrix up to date, or keeping this maintenance-free check and letting the IT crowd handle the rest… (thanks Matthieu for getting me addicted :p)

tumblr_m3yz13kTE41rsxd68o1_500

 

Keep rocking LS!

#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

Create a JQuery searchbox for LightSwitch HTML pages

I have a LightSwitch project with a query that takes a single (optional) string parameter, then performs a case-insensitive search on the server (there’s only a couple of dozen records, so don’t worry about performance).  If I create a new screen in the HTML client based on this query, then I’ll quickly have something like:

Image 032

At run-time, this screen will look like:

Image 033

Cewl, easy money!

However, for no other reason than it being a cool Friday-afternoon-hacking-project, it would be nice if that textbox would look like an actual search control, and if we could move it to the command bar where there’s lots of pretty blue space going unused at the moment…

The trick is really easy: from the screen designer, turn the “SearchTerm” control into a “Custom Control”.  From Properties Panel, choose “Edit render code”.  In the generated method stub, change the code to:

myapp.BrowseTracks.SearchTerm_render = function (element, contentItem) {
    $(element).lightswitchsearchbox();
    $(element).lightswitchsearchbox("bindTo", contentItem);
    $(element).lightswitchsearchbox("render");
};

Wait, that’s it? LightSwitch has some kind of built-in lightswitchsearchbox method?  Nope, but my JQuery widget has 🙂  Just like before, find it on my github page, download, add to the project, and enjoy the result:

Image 034

 

Keep rocking LS!!!!!

What field do you use to store an Image?

When I started playing with the LightSwitch HTML bits, my first experiment was to try to recreate a professional mobile site.

After only a couple of minutes (minus the many hours spent creating a JQuery slider for LightSwitch first), the result looked like this (professional corporate mobile site on the left, 3 minutes of LightSwitch on the right):

719643839

 

The entire thing was done fiddling around in the IDE on a single screen on queries on the same entity.  This entity had simple properties like “Name”, “IsFeaturedInSlider”, “Link” and “ImageToShow”…

About that last property: in the SL client we all found it quite logical that an “ImageToShow” property, as a business type, was stored as an “Image” (data type: binary).  In the new HTML client however, you can have an entity of business type “Image”, “String” or “Web address”…

 

Image 012

 

And for each of these properties, you can select an “Image” control in the IDE…

Image 013

So here’s the question (under the assumption that you can choose – no existing data…): what field do you use to store an Image?

My personal and totally unfounded opinion: I’m a fan of storing my images as “Image”, because of the out-of-the-box support in the SL client.  However if and only if I’m absolutely sure there will never be need for this support, then I rather store them as a “Web Address”.  When stored as a simple url, a browser will actually be smart enough to cache the images locally and not re-fetch them every time, thus gaining a small but sometimes crucial performance gain.

What’s your take on this? Leave a comment below if you agree, or disagree. (Or just want to say hi 🙂 )

 

Keep rocking LS!

 

Create a JQuery slider for LightSwitch HTML pages.

A JQuery slider (also commonly referred to as a carousel) has very little use in the LOB world, but sometimes you want one anyways, just because it’s cool.

To get started, open up any “hello-HTML app” and create a screen.  On the ViewModel, add a collection (Speakers in this example) than drag it on View so that your screen looks similar enough to my example:

Image 011

In the HTML client, there’s only three supported “Collection controls”: the List, the Tile List and the CustomControl.  To create a slider, it’s actually smarter to select the built-in List control over creating a custom control from scratch.  After all, the simple combination above, at runtime, will already look pretty fancy:

Image 008

The only thing different between the built-in List and a Slider control, is that the List is showing all items at once.  Nothing a little JQuery can’t fix 🙂

I already prepped the code in a JQuery UI Widget so you can just download my switchtory.lightswitchslider and add it to the “Scripts” folder inside your HTML client project.  Don’t forget to load it as well: open the default.htm page and add:

    <script type="text/javascript" src="Scripts/switchtory.lightswitchSlider.js"> </script>

Now that the slider is part of your project, time to bind it to the collection & let it render.  Back in the screen designer, select the List control, and the first child element (Columns Layout in my example but Summary, Rows Layout, … whatever you made of it) and in Properties Window click the “Edit post-render code”.

Then glue it all together:

var slider; //Define a slider variable
myapp.Home.Speakers_postRender = function (element, contentItem) {
    slider = $(element); //Create the slider widget
    slider.lightswitchSlider({ timerInterval: 3000 }); //Initialize it
    slider.lightswitchSlider("bindToList", contentItem); ///Bind to the collection

};
myapp.Home.SpeakersTemplate_postRender = function (element, contentItem) {
    slider.lightswitchSlider("render", contentItem); //Last element? Time to render.
};

 

The slider widget has two methods (apart from the constructor with an optional timeInterval setting): “bindToList” (which grabs a hold of the actual VisualCollection, to find out how many elements are supposed to be loaded) and “render” (which grabs the HTML created by the LightSwitch default List, hides all the children and systematically unhides one child at a time…).

Press F5, you should only see one Speaker in your list:

Image 010

 

And if you wait a couple of seconds, that item will fade out and the next one will fade right back in.

Image 009

 

Awesome!

If you’re doing any fancy LightSwitch HTML customizations, remember: I showed you mine 🙂

 

Keep rocking LS!

 

PS: Because a Slider usually shows 3-12ish items in rotation, the code doesn’t handle asynchronous paging

Hide the Save/Cancel/Ok/Discard buttons in a LightSwitch HTML screen.

Today I’m going to hide the Save/Cancel/OK/Discard buttons in a LightSwitch HTML screen.  Why? Because it’s really cool.

On any screen, select the “Write code” button and find the “activated” event (I’m sure this is still on the planning, but the CTP4, which is the current version, only has a “created” event; However you can tap into the post_render method of the last control on your screen as a workaround) and type:

 

myapp.Home.SomeControlInMyHomeScreen_postRender = function (element, contentItem) {
    $("[data-ls-tap='tap:{data.shell.discardCommand.command}']").hide();
    $("[data-ls-tap='tap:{data.shell.saveCommand.command}']").hide();
    $("[data-ls-tap='tap:{data.shell.okCommand.command}']").hide();
    $("[data-ls-tap='tap:{data.shell.cancelCommand.command}']").hide();
};

The code uses a simple JQuery selector to find whatever HTML element has been rendered with a discard, save, ok or cancel command “attached to it” (the LightSwitch way), then uses the JQuery hide() method.

Bam, just like that. 

The code shows some interesting details about the way the LightSwitch HTML client attaches commands to an HTML element, once I understand any of it I’ll make sure to share 🙂

 

Keep rocking LS!