Quantcast
Channel: Category Name
Viewing all articles
Browse latest Browse all 10804

Dynamically setting column names on an editable grid (Babar Ismail)

$
0
0

LightSwitch gives us the ability to import data from numerous sources. This data can then be shown to the end user in an editable grid by simply creating editable grid screens based off that data.

The column names of the grid will correspond to the field names of the table we import. This works for most cases but in certain situations we need these column names to be dynamic. For example, consider an application for the Top 5 cars of the year with database designed as follows:

CarRating

AttributeName

Car1

Car2

Car3

Car4

Car5

Braking

Good

Very Good

Good

Good

Good

Acceleration

Excellent

Fair

Very Good

Very Good

Good

Top Speed

Excellent

Excellent

Very Good

Good

Fair

Handling

Very Good

Excellent

Fair

Fair

Good

Car

Name

Ranking

BMW

5

Mercedes

4

Porsche

3

Aston Martin

2

Ferrari

1

Now we want to show the Car Rating table to the user but instead of “Car1”, Car2”, etc. in our column names we want to read the Cars table, get the top 5 cars and replace the column names with the names we get from the table.

In order to do that we start off with creating the 2 tables above: CarRating and Car. CarRating will have string fields called AttributeName, Car1, Car2, Car3, Car4, Car5 and the table “Car” will have a string field called Name and an Integer Field called Ranking.

Here is the snapshot of what the tables looks like in LightSwitch:

image

image

Next we create an editable grid screen for CarRating. So right click the screens node from the Solution Explorer and click Add Screen. Select the Editable Grid Template and choose CarRatings as your Screen Data and name your screen CarRatingsGridScreen.

Now from the Solution Explorer, right click the CarRatingsGridScreen and select View Screen Code.

image

This will bring you to the code editor. Replace all the code with the following (make sure the namespace name is consistent with the rest of the user code files):

VB

Imports System.Collections.Generic
Imports Microsoft.LightSwitch
Imports Microsoft.LightSwitch.Presentation
Imports Microsoft.LightSwitch.Presentation.Extensions
Imports System.Windows.Controls

Namespace LightSwitchApplication

    Public Class CarRatingsGridScreen

        Private carRatingsGrid As DataGrid = Nothing

        Private Sub CarRatingsGridScreen_InitializeDataWorkspace(saveChangesTo As List(Of IDataService))
            AddHandler Me.FindControl("grid").ControlAvailable, AddressOf CarRatingsGrid_ControlAvailable
            UpdateColumnNames()
        End Sub

        Private Sub CarRatingsGrid_ControlAvailable(sender As Object, e As ControlAvailableEventArgs)
            Me.carRatingsGrid = DirectCast(e.Control, DataGrid)
        End Sub

        Private Sub UpdateColumnNames()
            If Me.carRatingsGrid Is Nothing Then
                Throw New InvalidOperationException("Grid cannot be null")
            End If

            Dim top5Cars = Me.DataWorkspace.ApplicationData.Cars.OrderBy(Function(car) car.Ranking).Take(5)
            'start with the second column
            Dim counter As Integer = 1
            For Each car As Car In top5Cars
                Me.carRatingsGrid.Dispatcher.BeginInvoke(
                    Sub()
                        Dim rowTemplate As IContentItem = DirectCast(Me.carRatingsGrid.DataContext, IContentItem).ChildItems(0)
                        Dim column As IContentItem = rowTemplate.ChildItems(counter)
                        column.DisplayName = car.Name
                        'counter is incremented in Dispatcher.BeginInvoke
                        counter += 1
                    End Sub
            )
            Next
        End Sub

    End Class
End Namespace

C#

using System;
using System.Collections.Generic;
using Microsoft.LightSwitch;
using Microsoft.LightSwitch.Presentation;
using Microsoft.LightSwitch.Presentation.Extensions;
using System.Windows.Controls;
namespace LightSwitchApplication
{
    public partial class CarRatingsGridScreen
    {
        DataGrid carRatingsGrid = null;
        partial void CarRatingsGridScreen_InitializeDataWorkspace(List<IDataService> saveChangesTo)
        {
            this.FindControl("grid").ControlAvailable += CarRatingsGrid_ControlAvailable;
            UpdateColumnNames();
        }

        void CarRatingsGrid_ControlAvailable(object sender, ControlAvailableEventArgs e)
        {
            this.carRatingsGrid = (DataGrid)e.Control;
        }

        private void UpdateColumnNames()
        {
            if (this.carRatingsGrid == null)
                throw new InvalidOperationException("Grid cannot be null");

            var top5Cars = this.DataWorkspace.ApplicationData.Cars.OrderBy(car => car.Ranking).Take(5);
            //start with the second column
            int counter = 1;
            foreach (Car car in top5Cars)
            {
                this.carRatingsGrid.Dispatcher.BeginInvoke(() =>
                {
                    IContentItem rowTemplate = ((IContentItem)this.carRatingsGrid.DataContext).ChildItems[0];
                    IContentItem column = rowTemplate.ChildItems[counter];
                    column.DisplayName = car.Name;
                    //counter is incremented in Dispatcher.BeginInvoke
                    counter++;
                });

            }
        }

    }
}

In the code above, the first thing we are doing is registering CarRatingsGrid_ControlAvailable method with the ControlAvailable event of our DataGrid. This is happening in the InitializeDataWorkspace method.

When the DataGrid on the screen shows up, our CarRatingsGrid_ControlAvailable method will fire. This method has an argument of type ControlAvailableEventArgs from which we can get the actual Silverlight control. So we declare a DataGrid in our class and set it to e.Control in the method.

Next we call the UpdateColumnNames method from InitializeDataWorkspace. In UpdateColumnNames, we get the top 5 cars, traverse through each of them and set the names of the corresponding datagrid column.

Note that we are setting the column names of the datagrid on the UI thread. If we don’t include the Dispatcher.BeginInvoke, we will get an UnauthorizedAccessException. Secondly, since it is an async operation, we have to increase the counter in the Dispatcher.BeginInvoke otherwise we may get inconsistent results.

Now in order to verify that it works, you will need to add a few “Car” records. So create an editable grid screen for the Car table and add a few records. Now open a new instance of the CarRatingsGridScreen. It should have the updated column names.

Here is a screenshot of how the screens should look like at runtime:

image

 

image

Although this post is about setting the column names dynamically, it can be extended into any sort of UI manipulation. For example, we can get a handle to a textbox control in a list and details screen and set its background to yellow based on a computation or we can change the font color of a data grid cell. The same concept applies – get a handle to the underlying Silverlight control and change any property you want on the UI thread.

Happy Coding!!!


Viewing all articles
Browse latest Browse all 10804

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>