Using Custom Controls to Enhance Your LightSwitch Application UI - Part 1 (Karol Zadora-Przylecki)

Using Custom Controls to Enhance Your LightSwitch Application UI - Part 1 (Karol Zadora-Przylecki)

Rate This
  • Comments 20

Visual Studio LightSwitch provides a set of standard UI controls for displaying application data. These controls include common Windows UI elements like text boxes, as well as controls tailored for the data entry and editing tasks (like address viewer or data grid). Many applications can be built with only standard LightSwitch controls, but there are applications that require more advanced visualizations (e.g. charts or maps), or just have specific requirements that are not covered by standard control set. One possibility to address these requirements is to use a non-standard LightSwitch control. LightSwitch provides extensibility points for the 3rd party control vendors to extend the set of control available inside the IDE. From application development perspective they behave just like built-in controls—they show up in the same places in the IDE and their general working is no different from standard controls, so using them is very easy. The downside is that if a 3rd party control that satisfies the given scenario is not available, implementing one might be a task too difficult or labor-intensive for typical LightSwitch user. Fortunately there is an easier way: LightSwitch applications can use Silverlight “custom” controls directly, and re-using or authoring custom controls is much easier.

Custom controls defined

LightSwitch client application uses Silverlight framework as the foundation to build upon. LightSwitch controls are at the core just Silverlight controls, but they are enhanced with information and functionality that makes it possible for LightSwitch runtime to relieve the developer from many routine tasks associated with UI data binding, UI layout and command enablement. A custom control is a regular Silverlight control that is part of LightSwitch application UI (a screen). The main difference between LightSwitch controls and custom controls is that a custom control does not have LightSwitch-specific information associated with it. Therefore LightSwitch treats it as a “black box” and it is up to the developer to specify what data the control should display (data-bind the control to the screen) and to handle any events the control might raise. There are two possibilities here:

  • The control might be built for a particular screen or entity (with intimate knowledge of the members of some screen or entity). For example, if we are building a custom control to display Customer data in a visually-rich way, we might explicitly bind parts of the control to Customer properties such as Name and Address. The advantage of this approach is that using this control will require little or no code, but obviously it cannot be used to display any other piece of data other than a Customer, so we lose some flexibility and reuse opportunities.
  • The control might have no knowledge of the data it will display or the screen it will use—all data binding and interaction with the control can be specified in screen code. With this approach the control can be reused across different screens and applications. The drawbacks include the fact that there is more code to write and furthermore, the screen code targets a specific control which makes the screen harder to modify down the road. This goes against the notion of screen code being pure business logic.

In practice both of these two approaches can be used, even for a single control, and it is up to the developer to decide which one is more advantageous, given unique application requirements. An example will make things clearer, but before we jump into it,  we need to learn how exactly custom controls show up on a screen.

Screen content tree and (custom) controls

A screen in a LightSwitch application is built of three elements:

  1. Screen members are what you see on the left in the screen designer inside LightSwitch IDE. They are the data the screen is operating on. Screen members can include collections of entities, single entities and scalar values. They can also include commands (both built-in and user-defined)
  2. Screen content tree defines the visual layout of the screen. It determines what is shown on the screen and how the information is visually arranged. Content tree consists of content items and it is shown on the right side of the screen designer. Some content items are used just for layout, but most are there to show a specific piece of screen data. In other words they are bound to a piece of data, or have a data binding. Content items can also have an associated control (visual) that will be used to visualize the item when the application is running.
  3. Screens can also have user code, which can be used to customize screen behavior programmatically and implement business logic. Screen code can be shown by clicking “Write Code” button in screen designer toolbar.

The screenshot below shows design view of a screen called ShipperListDetail. 

CustomControls_F1

Note how screen designer shows the associated control and the data binding for content items that have them. If you want to know more how content tree, controls and screen members work together please see The Anatomy of a LightSwitch Application Series Part 2 – The Presentation Tier.

So what does all this have to do with custom controls? Well, the way you add a custom control to a screen is by replacing the standard (default) control that LightSwitch assigns to a content item with a custom control. In the example above we have done it for the last control in the content tree and we will now show you how

Example: using Rating control for showing shipper rating

Let’s say we have a database of shippers that are available to ship goods from our manufacturing facility to various parts of the country. For now we will focus only on three pieces of information: shipper’s name, phone number and rating. Open Visual Studio, create a new LightSwitch project (you can call it “CustomControls”) and add a Shippers entity:

CustomControls_F2

Also, our business rules state that shipper rating, if known, must be a number between 1 and 5, so click the Rating column in table designer, go to Properties window, find the “Custom Validation” link at the bottom of the property sheet for the Rating column and add the following code (only the body of the Rating_Validate method needs to be modified)

C#
public partial class Shipper
    {
        partial void Rating_Validate(EntityValidationResultsBuilder results)
        {
            if (this.Rating.HasValue)
            {
                if (this.Rating < 1 || this.Rating > 5)
                {
                    results.AddPropertyError("Shipper rating (if known) must be between 1 and 5");
                }
            }
        }
    }

 

VB
Public Class Shipper
        Private Sub Rating_Validate(ByVal results As EntityValidationResultsBuilder)
            If Me.Rating.HasValue Then
                If Me.Rating < 1 Or Me.Rating > 5 Then
                    results.AddPropertyError("Shipper rating (if known) must be between 1 and 5")
                End If
            End If
        End Sub
    End Class

Next create a List and Details screen for Shippers entity, including details for the entity on the screen. Your screen should look like this in the designer:

CustomControls_F3

Now we are ready to create the custom control to display the rating. We will use the Rating control from Silverlight toolkit, so if you do not have the toolkit installed yet, you can get it from http://silverlight.codeplex.com/. After you have the toolkit installed, right-click the solution node in Solution Explorer and choose Add | New Project. Choose Silverlight Class Library project and name it RatingControlWrapper. Choose Silverlight 4 as the target Silverlight version and delete the Class1 class automatically created as part of the project.

Note: this you won’t be able to complete this portion of the example (creating custom control wrapper) if you have only Visual Studio LightSwitch Beta 1 installed on your machine. You need both Visual Studio Professional (or higher SKU) and Visual Studio LightSwitch. This is because Silverlight class library projects are not supported by Visual Studio LightSwitch alone. Later on I will show you how to use Rating control directly and set up control binding from LightSwitch code; that does not require anything other than Visual Studio LightSwitch. Also, this portion of the example assumes familiarity with Silverlight user controls and XAML; for more information about these topics see Getting Started with Controls in Silverlight documentation.

After the project is created, right-click the project node and choose Add | New Item. Choose a Silverlight User Control item type and name the new control RatingControlWrapper. After the project is created, add a reference to System.Windows.Controls.Input.Toolkit assembly. You will find it under the directory where Silverlight toolkit is installed; on my machine it was “C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Bin”. Next open the RatingControlWrapper.xaml file in XAML view, add a namespace declaration for the local and toolkit namespaces and finally add the Rating control itself to the content of our wrapper control. You should end up with XAML file that has the content shown below; we have highlighted the portions of the control XAML that we have changed. Note that we have replaced the default Grid layout for the content with a simpler StackPanel; this will come in handy later.

RatingControlWrapper.xaml
<UserControl x:Class="RatingControlWrapper.RatingControlWrapper"
   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:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"   
   xmlns:local="clr-namespace:RatingControlWrapper"
    mc:Ignorable="d"
   d:DesignHeight="25" d:DesignWidth="300">

    <StackPanel Orientation="Horizontal">
        <inputToolkit:Rating ItemCount="5" HorizontalAlignment="Left" SelectionMode="Continuous" x:Name="RatingControl"
                             Value="{Binding Path=Screen.ShipperCollection.SelectedItem.Rating, Mode=TwoWay}">
                </inputToolkit:Rating>
    </StackPanel>
</UserControl>

The most interesting portion of this code is the data binding specification: it binds the Rating control’s Value property (which controls how many rating “stars” the user sees, i.e. depicts the rating) to Screen.ShipperCollection.SelectedItem.Rating property. The TwoWay mode means that whenever one side of the binding changes, the other side will be updated. The default binding mode in Silverlight is OneWay, which means that UI reflects (screen) data; but changes in the UI do not affect the underlying data. We want the user to be able not only see the rating, but also to change the rating by clicking the control, giving a shipper desired number of “stars”, so we use TwoWay.

Now we can switch to our main project and replace the textbox that is used for the Shipper.Rating property with our custom control. Right-click the RatingControlWrapper project in the Solution Explorer and choose “Build”—it should build without errors. Open ShipperListDetail screen from our main application in the designer, select the Rating content item and open the control selection dropdown:

CustomControls_F4

Choose “Custom Control” here. Switch to Properties window, scroll to Custom Control property and hit Change link—Add Custom Control window appears

CustomControls_F5

Click “Add Reference” button, switch to Project tab and select RatingControlWrapper project. Hit OK to add project reference—you should now see the RatingControlWrapper assembly in the Add Custom Control dialog (see screenshot above). Expand the RatingControlWrapper namespace, select the RatingControlWrapper control and hit OK.

Handling data conversions and null values

At this point you could try to run the application and start adding some shippers. Our rating UI shows up, but does not quite work as expected—it seems like the only rating that sticks is five stars. Also there is no obvious way to clear the rating either. How can we fix this?

 

The first problem stems from the fact that the Value property of the Rating control is a floating-point number and Shippers.Rating column is an integer. We could store floating point numbers instead of integers for our rating otherwise we need to convert the Shipper’s rating of 1, 2, 3, 4 or 5 into 0.0 to 1.0 range that the Rating control can work with. Fortunately Silverlight has a concept of a value converter that is designed for just that. So let’s create a value converter for our control wrapper. Add a new class to the RatingControlWrapper project and name it Int2DoubleConverter. Then change the class code to this:

 

C#
using System;
using System.Diagnostics;
using System.Windows.Data;


namespace RatingControlWrapper
{
    public class Int2DoubleConverter: IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null) return null;

            double retval = System.Convert.ToDouble(value);
            
            double scalingFactor;
            if (double.TryParse(parameter as string, out scalingFactor))
                retval /= scalingFactor;

            return retval;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null) return null;

            double retval = (double) value;
            
            double scalingFactor;
            if (double.TryParse(parameter as string, out scalingFactor))
                retval *= scalingFactor;

            return System.Convert.ToInt32(retval);
        }
    }
}

 

VB
Imports System.Diagnostics
Imports System.Windows.Data


Public Class Int2DoubleConverter
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
    Implements IValueConverter.Convert
        If value Is Nothing Then
            Return Nothing
        End If

        Dim retval As Double = System.Convert.ToDouble(value)

        Dim scalingFactor As Double
        If Double.TryParse(CStr(parameter), scalingFactor) Then
            retval /= scalingFactor
        End If

        Return retval
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
    Implements IValueConverter.ConvertBack
        If value Is Nothing Then
            Return Nothing
        End If

        Dim retval As Double = CDbl(value)

        Dim scalingFactor As Double
        If Double.TryParse(CStr(parameter), scalingFactor) Then
            retval *= scalingFactor
        End If

        Return System.Convert.ToInt32(retval)
    End Function
End Class

To make the converter work for various number ranges we are going to use a parameter (scaling factor). In our case the maximum rating is 5 and we will use this value as the scaling factor. Now open the RatingWrapperControl in the designer and add the converter infromation to the binding:

RatingControlWrapper.xaml
<UserControl x:Class="RatingControlWrapper.RatingControlWrapper"
   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:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"   
   xmlns:local="clr-namespace:RatingControlWrapper"
   mc:Ignorable="d"
   d:DesignHeight="25" d:DesignWidth="300">

    <UserControl.Resources>
        <local:Int2DoubleConverter x:Key="I2DConverter" />
    </UserControl.Resources>
    
    <StackPanel Orientation="Horizontal">
        <inputToolkit:Rating x:Name="RatingControl" ItemCount="5" HorizontalAlignment="Left" SelectionMode="Continuous"
                            Value="{Binding Path=Screen.ShipperCollection.SelectedItem.Rating, Mode=TwoWay,
                            Converter={StaticResource I2DConverter}, ConverterParameter=5 }">
                </inputToolkit:Rating>
    </StackPanel>
</UserControl>

Changing a shipper’s rating to unknown requires setting the underlying property to null, but the Rating control does not have this capability built-in. We can add it by using a link label and a bit of code. Add the following line to RatingControlWrapper.xaml:

RatingControlWrapper.xaml
<UserControl x:Class="RatingControlWrapper.RatingControlWrapper"
   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:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"   
   xmlns:local="clr-namespace:RatingControlWrapper"
   mc:Ignorable="d"
   d:DesignHeight="25" d:DesignWidth="300">

    <UserControl.Resources>
        <local:Int2DoubleConverter x:Key="I2DConverter" />
    </UserControl.Resources>
    
    <StackPanel Orientation="Horizontal">
        <inputToolkit:Rating x:Name="RatingControl" ItemCount="5" HorizontalAlignment="Left" SelectionMode="Continuous"
                            Value="{Binding Path=Screen.ShipperCollection.SelectedItem.Rating, Mode=TwoWay,
                            Converter={StaticResource I2DConverter}, ConverterParameter=5 }">
               </inputToolkit:Rating>
     <HyperlinkButton Content="Clear" x:Name="hyperlinkButton1" Padding="4,0,0,0"
                      VerticalContentAlignment="Center" Width="50" Click="OnClearAction" />
    </StackPanel>
</UserControl>

Double-click the OnClearAction in XAML editor—this should result in opening the code-behind file for the control (RapidControlWrapper.xaml.cs or RapidControlWrapper.xaml.vb, depending on the language you use). Change OnClearAction method body to

C#
private void OnClearAction(object sender, RoutedEventArgs e)
        {
            this.RatingControl.Value = null;
        }

 

VB
Private Sub OnClearAction(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Me.RatingControl.Value = Nothing
    End Sub

That is it. Now you can launch the application and it works as expected

CustomControls_F6

Setting up data binding via code

Our application works, but the data binding for our control is hard-coded into control definition. If the screen members change and the data binding path becomes invalid, the application will no longer work. I will now show you how to specify data binding for custom controls in screen code. In this way each screen can data-bind to the control in its unique way, so you can reuse the control with multiple screens.

First, open control definition again and remove the whole Value property binding. You can also delete the Int2DoubleConverter declaration from control resources. On the other hand, we want to expose the inner Rating control from our wrapper so that we can set a binding on it, so we’ll add the FieldModifier attribute to the control declaration. The XAML should now look like this

RatingControlWrapper.xaml
<UserControl x:Class="RatingControlWrapper.RatingControlWrapper"
   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:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"   
   xmlns:local="clr-namespace:RatingControlWrapper"
   mc:Ignorable="d"
   d:DesignHeight="25" d:DesignWidth="300">

   <StackPanel Orientation="Horizontal">
        <inputToolkit:Rating x:Name="RatingControl" x:FieldModifier="public" ItemCount="5" HorizontalAlignment="Left" SelectionMode="Continuous" />                   
        <HyperlinkButton Content="Clear" x:Name="hyperlinkButton1" Padding="4,0,0,0" VerticalContentAlignment="Center" Width="50" Click="OnClearAction" />
    </StackPanel>
</UserControl>

Next open ShipperListDetails screen and override (screen)_Loaded method (in VB you will also have to add a reference to System.Windows.Controls.Input.Toolkit assembly to the client project). The Loaded method should look like this (including necessary namespace imports which you should put at the top of the file)

C#
using Microsoft.LightSwitch;
using System.Windows.Controls;
using System.Windows.Data;
using System.Diagnostics;
using RatingControlWrapper;

       partial void ShipperListDetail_Loaded()
       {
           IContentItemProxy proxy = this.FindControl("RatingControl");
           Debug.Assert(proxy != null);
           if (proxy == null) return;

           proxy.Invoke(() =>
           {
               var rw = proxy.Control as RatingControlWrapper.RatingControlWrapper;
               Debug.Assert(rw != null);
               if (rw == null) return;

               var rc = rw.RatingControl;

               var b =  new Binding("Value");
               b.Mode = BindingMode.TwoWay;
               b.Converter = new Int2DoubleConverter();
               b.ConverterParameter = "5";
               rc.SetBinding(Rating.ValueProperty, b);
           });
       }

VB
Imports System.Diagnostics
Imports System.Windows.Data
Imports System.Windows.Controls
Imports Microsoft.LightSwitch
Imports RatingControlWrapper


       Private Sub ShipperListDetail_Loaded()
           Dim proxy As IContentItemProxy = Me.FindControl("RatingControl")
           Debug.Assert(proxy IsNot Nothing)
           If proxy Is Nothing Then
               Return
           End If

           proxy.Invoke(Sub()
                            Dim rw = TryCast(proxy.Control, RatingControlWrapper.RatingControlWrapper)
                            Debug.Assert(rw IsNot Nothing)
                            If rw Is Nothing Then
                                Return
                            End If

                            Dim rc = rw.RatingControl

                            Dim b = New Binding("Value")
                            b.Mode = BindingMode.TwoWay
                            b.Converter = New Int2DoubleConverter()
                            b.ConverterParameter = "5"
                            rc.SetBinding(Rating.ValueProperty, b)
                        End Sub)
       End Sub

For now let’s ignore the portion of the code that deals with finding controls and control proxies and focus on the last 5 lines where the data binding is set up. The binding mode and value converter setting look very similar to the previous example but where is the binding path?

Well, this is a different way to accomplish the same goal. Remember that the data context for a control is its content item.  The binding specification here binds the Rating control’s Value property to the content item’s Value property.  The content item does not just expose screen data; it has several properties that aid the UI layer (controls) in providing the best possible data editing experience. For example

  • DisplayName property is used for showing a caption
  • Description property can be used for a helpful tooltip
  • IsProcessing property indicates whether underlying data is available or still being loaded from the database
  • DataError property that contains error information if the data load fails
  • (there is more)

The full list of properties exposed by content items is beyond the scope of this post; but for our purposes Value property is the most important and sufficient: this is the property that returns the underlying piece of screen data that the content item represents. In our case the content item represents Shipper.Rating property, so the Rating.Value will be bound to Shipper.Rating, which is exactly what we want.  The only thing remaining is to make sure that the control has the Name property set to “RatingControl” in LightSwitch screen designer, otherwise our code won’t work.

CustomControls_F7

Run the application and verify that it still behaves properly.

Summary

In this post we have seen how you can use custom Silverlight controls to enhance UI of LightSwitch applications. We have learned how custom controls plug into screen content tree and how to bind them to screen data, both from XAML as well as from code. We also used a value converter to overcome the problem of type mismatch between control property types and entity member types and added a control gesture to set the underlying data to null. In the second part of this post we will talk about how LightSwitch run time uses threads and what implications this has on controls and screen code. We will also cover some ways of making the screen and the control work together (interact) and we will show you how to make custom controls work with hierarchical data.

Update for LightSwitch Beta 2 and LightSwitch 1.0

In LightSwitch Beta 2 Microsoft made some changes to make coding for custom controls more understandable and reliable. First, we changed the name of the screen’s “Loaded” method to “Created”. This is to avoid confusion with any data load operations—the method is called immediately after the screen UI is created and at that time the initial data load (if any) might still be in progress. This has no impact on custom control data binding because custom controls will be notified automatically when data becomes available.

More important changes are related to FindControl method and the IContentItemProxy interface it uses:

  1. IContentItemProxy now has a SetBinding method that lets you add data bindings to your custom control in one line of code, without having to switch to UI thread.
  2. If you need to set some custom control properties directly (without using data binding), you will need to hook up the new IControlItemProxy.ControlAvailable event. The old IContentItemProxy.Control property is gone. The reason for this change is that Silverlight handles control creation and unload internally and, for performance reasons, may delay its until it the very last moment, which is depends on what the end user is doing to the application. For example, if you use a Tabs control on your screen and the custom control is on a tab that is not shown initially (is not the first tab), Silverlight will not create the control until its parent tab is activated by the user. This made the usage of the old IControlItemProxy.Control property very tricky and unreliable. In LightSwitch Beta 2, the LightSwitch run time will call your code (event handler) when the control is created and your code can access the control (via passed-in parameter) in a safe and reliable way.

The following snippet illustrates the usage of these APIs in a simple example:

C#
partial void ShippersListDetail_Created()
{
    var ctrlProxy = this.FindControl("RatingControl");
    ctrlProxy.SetBinding(Rating.ValueProperty, "Value", BindingMode.TwoWay);
    ctrlProxy.ControlAvailable += this.OnRatingControlAvailable;
}

void OnRatingControlAvailable(object sender, ControlAvailableEventArgs e)
{
    Rating rc = e.Control as Rating;
    rc.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
    rc.ItemCount = 5;
    rc.SelectionMode = RatingSelectionMode.Continuous;
}

 

VB
Private Sub ShippersListDetail_Created()
    Dim ctrlProxy = Me.FindControl("RatingControl")
    ctrlProxy.SetBinding(Rating.ValueProperty, "Value", BindingMode.TwoWay)
    AddHandler ctrlProxy.ControlAvailable, AddressOf Me.OnRatingControlAvailable
End Sub

Private Sub OnRatingControlAvailable(sender As Object, e As ControlAvailableEventArgs)
    Dim rc As Rating = TryCast(e.Control, Rating)
    rc.HorizontalAlignment = System.Windows.HorizontalAlignment.Left
    rc.ItemCount = 5
    rc.SelectionMode = RatingSelectionMode.Continuous
End Sub
Leave a Comment
  • Please add 2 and 5 and type the answer here:
  • Post
  • Karol, you have an awesome communication skills. Just loved the write up. I also liked how you gave us that scare first, where the control was tied directly to the LS property in the XAML binding and then showed how it cab be used generically multiple places by binding the data via code.

    Although it's too late, but I'd just not to use the same name for the "Custom Library project" and the "control", since it gets confusing.

    BTW, where did this name come from? :-)

    (RapidControlWrapper.xaml.cs or RapidControlWrapper.xaml.vb, depending on the language you use)

    I really would love to see more blogs from you. I know when I finish your blog, I've learned something new. :-)

    Thanks!

    ..Ben

  • Karol, the steps to do to create a custom control, wasn't so bad. But as of Beta 2, is it still going to take the same number of steps or has it been more streamed line?

    Thanks!

    ..Ben

  • One other question Karol; Let's say when we are building app in Silverlight and using XAML, we drop a control either in the XAML editor or on the designer surface. From there, us as developers add the needed properties for the control and adjust the size and location on the surface to make it fit. Some large controls, like third party control, i.e. a Scheduler that may have many properties and settings can be done via initial XAML and some at runtime. But we, as developers tend to make those decisions (mostly at design time).

    Now suppose using those bigger controls (and not a rating control that has fixed size and fixed attributes) and try to incorporate into LS. Are we going to face a much bigger challenge from LS runtime trying to fit this into screen on it's own?

    My real question is, do you really see using custom controls more of using "Simple" controls or it really doesn't matter simple/small or complex/big controls can be used as well?

    With custom controls (if truly there is no restriction in using), the sky is the limit, since there are some great controls out there.

    Hope we can dig deeper into this.

    Thanks!

    ..Ben

    p.s. sorry for too many posts, I guess I'm excited! :-)

  • Ben, thank you for kind words of encouragement, I will try to do my best to keep up my blogging. Let me try to answer your questions.

    When we (at Microsoft) were discussing the custom control feature, we envisioned it as a kind of "escape hatch" for LightSwitch developers. We did not want to force them to use this feature routinely (e.g. on every screen)--we believe that standard controls and 3rd party LightSwitch controls provide best value in terms of productivity and simplicity and they should be sufficient to construct most of the UI in LightSwitch apps. If this is not the case, we will try hard to fix this, and our preferred way to do so would be to enhance the set of standard controls rather than make it very easy to consume custom controls . Having said that, we realize that custom controls are useful and important scenario and they will be fully supported; it is just that they require some setting up and some code to facilitate data binding and communication between the control and the screen.

    In terms of the improvements related to custom controls, for the final LightSwitch version there will be some improvements to screen APIs and to layout algorithms used by screen run time. These changes will not substantially alter developer experience, but they will streamline and simplify many tasks and custom controls should benefit too. I plan to cover one particular new API: IContentItemProxy.SetBinding in part 2 of this post. Full overview of screen APIs and screen layout is beyond the scope of this post and will probably have to wait till next public LightSwitch release becomes available.

    Regarding simple vs. complex controls, I do not see any particular problem with consuming complex controls in LighSwitch. LightSwitch introduces only a few additional concepts/limitations compared to vanilla Silverlight apps when it comes to incorporating SL controls in the UI, mostly around threading. This is something I wanted to cover in part 2 of this post--stay tuned. I believe that if you keep those LightSwitch-specific rules and caveats in mind, you should be able to use your favorite Silverlight controls in LightSwitch apps with very little extra work, no matter the size/complexity of the control in question. At least this is the design goal :-)  

    Hope that helps! Cheers!

    Karol

  • Karol, thank you for a well-informed reply!

    ..Ben

  • Thanks Karol,

    Can you tell us where the dependency property "rating" comes from? This is the one used when setting the binding. E.g. rc.SetBinding(Rating.ValueProperty, b) .

    I can't seem to set the value property to the custom control on the ListDetail screen.

    Cheers,

    - Paul

  • ...never mind. Found it.

    I had to add the System.Windows.Controls.Input.Toolkit reference to the LightSwitch Client project (via File View). Once the reference was made, the dependency property was resolved.

    Thanks!

  • Great article Karol!

    Very well explained. Looking forward to Part 2. Any idea when that will be?

    Thanks,

    Yann

  • Another change for Beta2.  

    I believe Beta2 changed the name of collections.

    In the RatingControlWrapper.XAML file

    This

    Screen.ShipperCollection.SelectedItem.Rating

    Should become this

    Screen.Shippers.SelectedItem.Rating

  • Yes, you are right, Dan. Thanks for pointing this out.

    Karol

  • Karol,

      Good tutorial, I love that we have the ability to add custom controls to LS.  It really opens doors to allow us to customize our applications.  

       One question I had that I can't seem to find an answer to, is how do you get a custom control to display data INSIDE a grid (or list)?  Say I want to show a small chart or gauge in a column of my datagrid.  How do I set my custom control bindings to show data for each row?

  • Hi guys I made a screen which is not based on any Entity and want to add a custom control e.g. a textArea on that screen. How can I bind that custom control with a property of some entity which is associated to some other screen in same project?

    Thanks in advance

  • Hi Ben,

    Great write up.  Question: Can you embed custom controls if you are using the web application type too?

    Thanks,

    John

  • Excellent article, thank you Karol. We are now waiting for Part II !!!

  • Karol wrote an article for CoDe Magazine that incorporates both part 1 and what he was going to post for part 2.

    Check it out: blogs.msdn.com/.../using-custom-controls-to-enhance-lightswitch-application-ui-karol-zadora-przylecki.aspx

    Enjoy!

Page 1 of 2 (20 items) 12