Alessandro Del Sole's Blog

/* A programming space about Microsoft® .NET® */
posts - 159, comments - 0, trackbacks - 0

My Links

News

Your host

This is me! This space is about Microsoft® .NET® and Microsoft® Visual Basic development. Enjoy! :-)

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.

Microsoft MVP

My MVP Profile

I'm a VB!

Watch my interview in Seattle

My new book on VB 2015!

Pre-order VB 2015 Unleashed Pre-order my new book "Visual Basic 2015 Unleashed". Click for more info!

My new book on LightSwitch!

Visual Studio LightSwitch Unleashed My book "Visual Studio LightSwitch Unleashed" is available. Click the cover!

Your visits

Follow me on Twitter!

CodePlex download Download my open-source projects from CodePlex!

Article Categories

Archives

Post Categories

.NET Framework

Blogroll

Help Authoring

Microsoft & MSDN

Setup & Deployment

Visual Basic 2005/2008/2010

Advanced LightSwitch: calling built-in search from Silverlight controls (Visual Basic)

I'm migrating a big Silverlight 4 project to LightSwitch and I'm at a point in which I need to implement search screens and editable grids. My requirement was using the RadGridView control from Telerik, replacing the built-in DataGrid of LightSwitch.

This implies creating a custom control. If you want to see an example, you can see my previous post about using the Telerik RadGridView in LightSwitch. The problem is that when you implement a custom control you also lose the built-in search box and data paging control, which are offered by search screens.

So my goal was implementing search in a custom control, and possibily invoking the built-in search functionality of LightSwitch without reinventing the wheel.

First, let me thank Eric Erhardt and John Stallo from the LightSwitch Team who pointed me to the right direction. Next, I suggest you to read this great article from Michael Washington who explains how to call LightSwitch methods from a Silverlight control. We'll use some techniques that Michael described in a great way.

Ok, let's go. What we need to implement is something like this:

I'm basing the current example on the Products table from the Northwind database. I have added a Silverlight class library to my solution and added a user control. Refer to my aforementioned blog post for the steps required to create a user control and how to add references to Telerik assemblies. This is the simplified XAML that defines the user interface:

<UserControl x:Class="HelperControls.GridControl"
    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"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="400" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">
 
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Search:" Margin="5"/>
            <TextBox Name="SearchBox" Margin="5" Width="200"/>
            <Button Content="Go!" Name="SearchButton" Margin="5" Width="50"/>
        </StackPanel>
        <telerik:RadGridView Name="ProductsGrid" AutoGenerateColumns="False" Grid.Row="1"
                             ShowColumnFooters="False" ShowGroupPanel="False" 
                             ItemsSource="{Binding Screen.Products}" SelectedItem="{Binding Screen.Products.SelectedItem, Mode=TwoWay}">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding ProductName}"/>
                <telerik:GridViewDataColumn Header="Quantity per Unit" DataMemberBinding="{Binding QuantityPerUnit}"/>
                <telerik:GridViewDataColumn Header="Unit Price" DataMemberBinding="{Binding UnitPrice, StringFormat=c}"/>
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
        <telerik:RadDataPager Name="RadPager1" PageSize="45" Grid.Row="2" IsTotalItemCountFixed="True" Source="{Binding Screen.Products}"/>
    </Grid>
    
</UserControl>

Now add to the Silverlight project a reference to the Microsoft.LightSwitch.dll and Microsoft.LightSwitch.Client.dll assemblies, that you can find in C:\Program Files\Microsoft Visual Studio 10.0\LightSwitch\1.0\Tools. Next, add a reference to the Common project of the LightSwitch solution. Adding these references is important in order to interact from Silverlight with LightSwitch.

Next, enable the File View in Solution Explorer. This is the point in which the article from Michael provides useful directions. Expand the Common project, then expand the UserCode folder. Add a new code file called IProductEntity.vb, then in the code file you implement the following interface:

Namespace LightSwitchApplication.UserCode
 
    Public Interface IProductEntity
 
        Sub SearchCollection(ByVal searchKey As String)
 
    End Interface
End Namespace

This interface defines a SearchCollection method, whose only argument is the search key that will be passed to the built-in search feature. Implementing an interface is a good practice because makes our custom method more easily recognizable in the LightSwitch search screen. Now switch back to the Logical View and open the search screen you want to customize, in my case this was an Editable Grid called Editable Products Grid.

The first thing is adding a local property of type String; this will receive the search key from the Silverlight control. Click Add Data Item, then specify the local property like this:

Remember that you must unselect the Is Required property in the Properties window.

Now in the upper-right corner of the Screen Designer click Write Code. We need to add the magic that will expose the search API (note that this is not documented). Add the following declaration at the class level:

        Dim loader As Microsoft.LightSwitch.Details.Client.IScreenCollectionPropertyLoader = _
             CType(Me.Details.Properties.Products.Loader, Microsoft.LightSwitch.Details.Client.IScreenCollectionPropertyLoader)

The IScreenCollectionPropertyLoader provides access to the objects that are responsible for working with the screen collection, including the built-in search feature. Once you have an instance of this object (remember to replace Products with the name of your collection), you invoke its SetSearchTerms method. This is the one that retrieves the desired set of data and receives an array of SearchTerm objects, each containing a word to search. If you want to restore the original result with the full collection, you simply pass an empty array.

To accomplish this invocation, you need to add a method. This will call the search feature. Click again Add Data Item, then Method and set a method name like this:

Once the method appears in the screen members list, right-click it and select Edit Execute Code. This is how the method implementation looks like:

    Private Sub CustomSearch_Execute()
        ' Write your code here.
        If String.IsNullOrEmpty(Me.SearchKey) Then
            loader.SetSearchTerms(New SearchTerm() {New SearchTerm("")})
        Else
            loader.SetSearchTerms(New SearchTerm() {New SearchTerm(Me.SearchKey)})
        End If
    End Sub
 
    Public Sub SearchCollection(searchKey As StringImplements UserCode.IProducts.SearchCollection
        Me.SearchKey = searchKey
        Me.Details.Dispatcher.BeginInvoke(Sub()
                                              CustomSearch_Execute()
                                          End Sub)
    End Sub

The method simply checks the content of the newly added screen property that holds the search terms. It simply decides what the best argument to pass to SetSearchTerms is. Notice how the code is offering a custom method called SearchCollection, which receives an argument of type String. This is a classic method, not bound to the screen and will be called by the Silverlight control; this is the reason why it receives an argument. This argument's value is assigned to the screen SearchKey property and then the CustomSearch method runs. Remember that this invocation must be performed in the appropriate thread, so this is why we are using the Dispatcher.

Now go to the code-behind of your Silverlight control, specifically to the Click event handler for the search button that you implemented previously. Add two Imports (or using in C#) directives to import the Microsoft.LightSwitch.Presentation and LightSwitchApplication.UserCode namespaces. Then, write the following handler:

    Private Sub SearchButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgsHandles SearchButton.Click
        'Get a reference to the LightSwitch DataContext 
        Dim objDataContext = CType(Me.DataContext, IContentItem)
 
        'Get a reference to the LightSwitch Screen
        Dim myScreen = CType(objDataContext.Screen, Microsoft.LightSwitch.Client.IScreenObject)
        'Converts the screen instance to hook our custom interface
        Dim management = CType(myScreen, IProductEntity)
 
        'Call the Method on the LightSwitch screen
        management.SearchCollection(Me.SearchBox.Text)
 
    End Sub

First you get the IContentItem instance from the control's DataContext. This allows accessing almost everything from the LightSwitch side. Next, you get the instance of the calling screen. Then you convert the instance of the screen into a type that represents our custom interface.

This allows invoking the SearchCollection method from the screen the usual way, passing the content of the TextBox as the search key. When you click the button, the query is executed on the LightSwitch side. The screen collection property will be updated with the search result and the Silverlight control's data context will be updated with the search result, so that all data-bound controls (including the RadGridView) will be updated without the need of writing code in the custom control.

Enjoy built-in search in your custom controls!

Alessandro

Print | posted on mercoledì 21 settembre 2011 02:54 | Filed Under [ Visual Basic Visual Studio LightSwitch ]

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 5 and 7 and type the answer here:

Powered by:
Powered By Subtext Powered By ASP.NET