Skip Navigation LinksHome > Articles > Silverlight > Silverlight DataGrid Template Column

Silverlight DataGrid Template Column

This article explains how to load user control inside silverlight DataGrid

By Keyur   On   Tuesday, 09 February 2010

Page Views : 406   |   Technologies : Silverlight

Rating : Rated :
0

Hello,

Recently in a project I had a request to display custom user control inside data grid.  I had to add separate user control as content element of Silverlight datagrid. This seemed interesting and was fun doing it. Finally I was able to get it done with Silverlight data grid.  I thought of sharing it online thinking somebody having similar requirements can leverage what I have done here.

 

Before we get started let’s see what I am talking about here. From whatever we do in this post will result in something similar to shown below.

 

 

Here I have created an imaginary company selling drinks all over the world and is comparing it’s current year’s sale with last year’s sales. And based on this comparison appropriate arrow should be displayed showing Increase/Descrease/Stable sale trend.

 

Note:-

Example taken here is for demonstration purpose only. In reality you can compute more complex logic and display it in datagrid.

 

So let’s get started.

 

Step 1:-

The first thing we have to do is to create a new Silverlight project and add references of two DLLs we will need to display datagrid on our Silverlight user control.

Step 2:-

The next step is to crate model class libraries into our application. For this add two projects “Class Library” and “Silverlight Class Library”. In a Class library Project add a class called CompanyData which is shown as below.

 

public class CompanyData

    {

        public int ItemId

        { get; set; }

        public string ItemName

        { get; set; }

        public double ThisYearSale

        { get; set; }

        public double LastYearSale

        { get; set; }

        public string Country

        { get; set; }

    }

 

Add this class file as a link into your silverlight class library projet. If you do not have idea how to do this please refer to my this MVVM article where I have demonstrated how to add an existing file as link in Visual Studio using screen shot. Now your project should look like as below. 

 

Step 3:-

Next step is to add Class library project as a reference to your Web project where we are planning to host our WCF service and add Silverlight Class Library as a reference to your Silverlight project. Please take a screen shot below.

 

 

 

 

Step 4:-

Now the next step is to add Silverlight enabled WCF services into your web project. Please do so and add a service method to it which will return some ComapnyData values are array. After this is done add the service reference to your Silverlight project. 

 

 

Make sure to do following by going into Advanced options while adding service reference as we are reusing same model classes both on server side and Silverlight side.

 

 

 

Step 5:-

Next we will add Silverlight datagrid to our MainPage.xaml as shown below.

 

<Grid x:Name="LayoutRoot">

        <data:DataGrid x:Name="customGrid" AutoGenerateColumns="False"                     

                       LoadingRow="customGrid_LoadingRow" VerticalAlignment="Top"

                       Width="310"

                       Height="200">

        </data:DataGrid>

</Grid> 

 

Add two user controls named ArrowColumn and TextColumn. The content of these files can be found with the attached source code.

 

ArrowColumn.xaml

<UserControl.Resources>

        <Style x:Key="SaleAbove" TargetType="Path">

            <Setter Property="Height" Value="8"/>

            <Setter Property="Width" Value="8"/>

            <Setter Property="Margin" Value="2,2,0,3"/>

            <Setter Property="Stretch" Value="Fill"/>

            <Setter Property="Fill" Value="White"/>

            <Setter Property="Data" Value="F1 M 10.6668,5.14984e-005L 18.6667,11.9998L 14.6667,11.9998L 14.6667,21.3332L 6.66664,21.3332L 6.66664,

                    11.9998L 2.66666,11.9998L 10.6668,5.14984e-005 Z "/>

        </Style>

 

        <Style x:Key="SaleEqual" TargetType="Path">

            <Setter Property="Height" Value="8"/>

            <Setter Property="Width" Value="8"/>

            <Setter Property="Margin" Value="2,2,0,3"/>

            <Setter Property="Stretch" Value="Fill"/>

            <Setter Property="Fill" Value="White"/>

            <Setter Property="Data" Value="F1 M 21.3334,10.6664L 9.33369,18.6664L 9.33369,14.6664L 0.000267029,14.6664L 0.000267029,6.66631L 9.33369,

                    6.66631L 9.33369,2.66634L 21.3334,10.6664 Z "/>

        </Style>

 

        <Style x:Key="SaleBelow" TargetType="Path">

            <Setter Property="Height" Value="8"/>

            <Setter Property="Width" Value="8"/>

            <Setter Property="Margin" Value="2,2,0,3"/>

            <Setter Property="Stretch" Value="Fill"/>

            <Setter Property="Fill" Value="White"/>

            <Setter Property="Data" Value="F1 M 10.6668,21.3333L 2.6669,9.33358L 6.66687,9.33358L 6.66687,0.000156403L 14.667,0.000156403L 14.667,

                    9.33358L 18.6669,9.33358L 10.6668,21.3333 Z "/>

        </Style>

 

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">

        <Canvas x:Name="SaleCanvas" HorizontalAlignment="Center" Height="12" Width="12" Grid.Column="0" >

            <Path x:Name="TrendPath" Width="8"  Height="8" Canvas.Left="0.29543"  Margin="2,2,0,3" Canvas.Top="0" Stretch="Fill" Fill="#FF336699" />

        </Canvas>

    </Grid>

As you can see I have defined three style namely sale trend above/equal/below with the taret type of Path. And in actual user control grid I have added a path named TrendPath with inside canvas.

 

ArrowColumn.xaml.cs

 

        public ArrowColumn()

        {

            InitializeComponent();

            Loaded += new RoutedEventHandler(ArrowColumn_Loaded);

        }

 

        void ArrowColumn_Loaded(object sender, RoutedEventArgs e)

        {

            CompanyData dataContext = (CompanyData)this.DataContext;

            double thisYearvalue = dataContext.ThisYearSale;

            double lastYearValue = dataContext.LastYearSale;

 

            if (thisYearvalue == lastYearValue)

            {

                TrendPath.Style = (Style)Resources["SaleEqual"];

            }

            else if (thisYearvalue < lastYearValue)

            {

                TrendPath.Style = (Style)Resources["SaleAbove"];

            }

            else if(thisYearvalue > lastYearValue)

            {

                TrendPath.Style = (Style)Resources["SaleBelow"];

            }

        }

 

The code behind file has above code which I will explain in a bit.f

 

TextColumn.xaml

 

<Grid x:Name="LayoutRoot" Background="White">

    <TextBlock x:Name="txtValue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,0,0,0"></TextBlock>

</Grid>

 

TextColumn.xaml.cs

 

public TextColumn()

{

InitializeComponent();

Loaded += new RoutedEventHandler(TextColumn_Loaded);

}

 

void TextColumn_Loaded(object sender, RoutedEventArgs e)

{

txtValue.Text = this.DataContext.ToString();

}

As you can see this user control has nothing else but just a text block.

 

In your MainPage.xaml file add following source code.

 

<UserControl.Resources>

        <DataTemplate x:Key="TextColumnTemplate" >

            <Grid HorizontalAlignment="Stretch" >

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*"/>

                    <ColumnDefinition Width="1"/>

                </Grid.ColumnDefinitions>

                <local:TextColumn ></local:TextColumn>

            </Grid>

        </DataTemplate>

        <DataTemplate x:Key="SaleColumnTemplate" >

            <Grid HorizontalAlignment="Stretch" >

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*"/>

                    <ColumnDefinition Width="1"/>

                </Grid.ColumnDefinitions>

                <local:ArrowColumn ></local:ArrowColumn>

            </Grid>

        </DataTemplate>

    </UserControl.Resources> 

 

 

Now comes the main part which will let us add this custom user controls into datagrid cell. The DataGrid declaration we have mentioned AutoGenerateColumns as false. So we will have to add columns by our self.

 

public MainPage()

{

InitializeComponent();

Loaded += new RoutedEventHandler(MainPage_Loaded);

}

 

void MainPage_Loaded(object sender, RoutedEventArgs e)

{

CompanyDataServiceClient client = new CompanyDataServiceClient();

client.GetCompanyDataCompleted += new EventHandler<GetCompanyDataCompletedEventArgs>(client_GetCompanyDataCompleted);

client.GetCompanyDataAsync();

}

 

void client_GetCompanyDataCompleted(object sender, GetCompanyDataCompletedEventArgs e)

{

if (e.Error == null)

{

AddColumnsToDataGrid();

customGrid.ItemsSource = ((CompanyData[])e.Result).ToList();

}

}

 

In the main page’s load event we created the WCF client and called a method GetComapnyData method. In it’s call back we did two things. First we called a function AddColumnsToDataGrid().

 

protected void AddColumnsToDataGrid()

{

for (int i = 0; i < 3; i++)

{

DataGridTemplateColumn column = new DataGridTemplateColumn();

switch (i)

{

 

case 0:

column.CellTemplate = (DataTemplate)Resources["TextColumnTemplate"];

column.Header = "Item Name";

break;

 

case 1:

column.CellTemplate = (DataTemplate)Resources["SaleColumnTemplate"];

column.Header = "Sale Trend";

break;

 

case 2:

column.CellTemplate = (DataTemplate)Resources["TextColumnTemplate"];

column.Header = "Country";

break;

 

default:

break;

}

customGrid.Columns.Add(column);

}

}

 

What we did here is added 3 template columns into our datagrid. Here we know how many columns we have to draw so we can do this manually. If you have to do this dynamically you can control this loop accordingly.

 

Next we did is set the list as ItemSource of the datagrid. Once this is done it will call LoadingRow event. We have captured this method. Let’s examine what we did.

 

private void customGrid_LoadingRow(object sender, DataGridRowEventArgs e)

{

for (int i = 0; i < customGrid.Columns.Count(); i++)

{

 

DataGridColumn column = customGrid.Columns[i];

FrameworkElement frameworkElement = column.GetCellContent(e.Row);

FrameworkElement result = GetParent(frameworkElement, typeof(DataGridCell));

if (result != null)

{

 

DataGridCell cell = (DataGridCell)result;

CompanyData currentRow = ((CompanyData)e.Row.DataContext);

switch (i)

{

case 0:

cell.DataContext = currentRow.ItemName;

cell.Tag = i;

break;

 

case 1:

cell.DataContext = currentRow;

cell.Tag = i;

break;

 

case 2:

cell.DataContext = currentRow.Country;

cell.Tag = i;

break;

 

}

}

}

}

 

As you can see in above code what we did is on loading of every row we captured the cell of all the columns in that row and assigned it’s datacontexts. In case of Column 1 we bound the entire company data as data context. As I mentioned above the code behind of ArrowColumn file will get this entire class as it’s data context.

 

On the loading of this control it will get the values of LastYearSale and CurrentYearSale and compare them. Rest is simple.

If

Current Year Sale > Last Year Sale =  UP Arrow

Current Year Sale < Last Year Sale =  DOWN Arrow

Current Year Sale = Last Year Sale = EQUAL Arrow

 

And the end result of this effort will be as shown below.

As I mentioned before, this is a very simple example and this idea can be extended to display very rich and useful information very easily leveraging other functionalities of DataGrid like Frozen Columns, etc.

 

Thanks

 

 

 

 


Keywords : using System.Windows.Controls
using System.Windows.Controls.Data;

Tags : Silverlight DataGrid UserControl inside DataGridDataTemplateItemTemplateDataGridTemplateColumn
Rate This Article :

Comments :
Write a Comment / Question / Feedback ...


User Login
Username :
Password :
Register Login

Forgot Password


Related Articles