Friday, April 10, 2009

Silverlight 3 : DataGrid Programming – Part 7

I have already discussed about DataForm, its usage and implementation in this series in my 3rd Article, Now today I am shifting my focus to DataGrid control, Those who are not much familiar with DataGrid, I request you to kindly visit my old Silverlight 2 Grid Binding article. Developers who are from ASP.NET background like me, knows the pain and efforts we need to take to customize DataGrid as per clients need, with this small introductory series, I am talking few things from which you will be able to create strong applications on top of that.

For this you need following assemblies mainly as :

  • System.Windows.Controls
  • System.Windows.Controls.Data
  • System.ComponentModel.DataAnnotations
  • System.Collections.Generic

To make this example simple and quick, I am making use of our traditional generics, In reality you can replace that Data part with your Database/Object whatever suits your application.

I am declaring one class with some properties like this :

public class sigheads
    {
        [Required(ErrorMessage = "Field Cannot be left Blank")]
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Invalid E-Mail ID")]
        public string Email { get; set; }
        [Range(0, 999, ErrorMessage = "Invalid Age")]
        public int Age { get; set; }
        public string SIG { get; set; }
        public DateTime WebCastDate { get; set; }
   }

If you have read my DataForm in Silverlight 3 article,you must have now drawn a conclusion why those [Required and [Regular like attributes are there and why we have System.ComponentModel.DataAnnotations namespace, This is for validating our data.After few lines I will put screenshot for your better understanding. Now lets write some few lines of code which will bind my this class and members to gird like this :

public List<sigheads> GetSIGHeads()
       {
           List<sigheads> sglst = new List<sigheads>();
           sglst.Add(new sigheads() { FirstName = "Vikram", LastName = "Pendse", Age = 27, Email = "vikram@dotnetcoe.com", SIG = "Silverlight", WebCastDate=Convert.ToDateTime("3/3/2009") });
           sglst.Add(new sigheads() { FirstName = "Mahesh", LastName = "Sabnis", Age = 40, Email = "mahesh@dotnetcoe.com", SIG = "WCF", WebCastDate = Convert.ToDateTime("3/4/2009") });
           sglst.Add(new sigheads() { FirstName = "Manish", LastName = "Sharma", Age = 28, Email = "manish@dotnetcoe.com", SIG = "WPF", WebCastDate = Convert.ToDateTime("3/5/2009") });
           sglst.Add(new sigheads() { FirstName = "Abhijit", LastName = "Gole", Age = 27, Email = "abhijit@dotnetcoe.com", SIG = "VC++", WebCastDate = Convert.ToDateTime("3/6/2009") });
           sglst.Add(new sigheads() { FirstName = "Varun", LastName = "Lokhande", Age = 27, Email = "varun@dotnetcoe.com", SIG = "MOSS-WSS", WebCastDate = Convert.ToDateTime("3/7/2009")});
           return sglst;
       }

Now,this we need to bind to our DataGrid like :

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
      dg.ItemsSource = GetSIGHeads();            
}

Our XAML code will be like this :

<Grid x:Name="LayoutRoot" Background="White" >
        <data:DataGrid x:Name="dg" Width="700" Height="300"
                       AlternatingRowBackground="Azure"
                       GridLinesVisibility="None"
                       SelectionMode="Single"
                       AutoGenerateColumns="False">
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Binding="{Binding FirstName}" Header="FirstName"/>
                <data:DataGridTextColumn Binding="{Binding LastName}" Header="LastName"/>
                <data:DataGridTextColumn Binding="{Binding Email}" Header="Email"/>               
                <data:DataGridTextColumn Binding="{Binding Age}" Header="Age"/>
                <data:DataGridTextColumn Binding="{Binding SIG}" Header="SIG"/>
                <data:DataGridTemplateColumn Header="WebCastDate" >
                    <data:DataGridTemplateColumn.CellTemplate>                      
                        <DataTemplate>
                            <my:DatePicker
                                SelectedDate="{Binding WebCastDate,Mode=TwoWay}">                               
                            </my:DatePicker>
                        </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>
                </data:DataGridTemplateColumn>
               <data:DataGridTemplateColumn Header=”Video”>
                    <data:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <HyperlinkButton x:Name="btnVideo" Content=" Video" Foreground="DarkBlue" Click="btnVideo_Click" ></HyperlinkButton>
                        </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>
                </data:DataGridTemplateColumn>
                <data:DataGridTemplateColumn>
                    <data:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <HyperlinkButton x:Name="btnDelete" Content=" Delete" Foreground="DarkBlue" Click="btnDelete_Click" ></HyperlinkButton>
                       </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>
                </data:DataGridTemplateColumn>
            </data:DataGrid.Columns>           
        </data:DataGrid>
    </Grid>

You can clearly see that I am binding columns explicitly with {Binding <Name of Field from sighead class>}, Also I am making use of DataTemplates where I am putting Links and Calendar control, well after few screenshots below you will automatically come to know what those DataTemplate does.So on building this much lines of code output will be :

BasicGrid

I think there is no need to say that sorting is by default and alternate row color is done by setting attribute of Grid as :

AlternatingRowBackground="Azure" 
GridLinesVisibility="None"
SelectionMode="Single"

AlternateRowBackground will set some color to alternate rows, Gridlines visibility can be set-reset and Selection Mode allows user to either select one row or multiple row at a time.

ValidGrid

I have already talked about  System.ComponentModel.DataAnnotations namespace which helps us to set validations over each field, so while editing you can see whether new data is valid or not as shown in above screen and this can be done using attribute over field like this :

[RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Invalid E-Mail ID")]
public string Email { get; set; }

You can see a small Calendar icon in grid which is done using DataTemplate and which helps to select date from calendar, XAML code above is self-sufficient to understand. Once you click on it, it will drop a full functional calendar like this :

CalGrid

Now you can see two links in Grid as “Video” and “Delete”, from Silverlight 2 we have a popup control, but as per tradition of my blog to explore new stuff, I am now making use of “Silverlight Child Window” , This template you will be able to get by Right clicking project ->Add New Item like this :

ChildPopup

This Child Window come with some by default XAML :

<Grid x:Name="LayoutRoot" Margin="2">
       <Grid.RowDefinitions>
           <RowDefinition />
           <RowDefinition Height="Auto" />
       </Grid.RowDefinitions>
       <TextBlock x:Name="Message" TextWrapping="Wrap" />
       <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
       <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
   </Grid>

Here beside <TextBlock> which I added up everything is by default. So by looking at those two buttons you must have guess what’s the use of this child window, I am using this here as some Alert box or it is rather something similar to Model Popup control in Ajax.

C# Code :

public partial class DeleteRecord : ChildWindow
    {
        int index = 0;
        public DeleteRecord(string wtlt,string msg,int idx)
        {
            InitializeComponent();

            index = idx;
            this.Title = wtlt;
            this.Message.Text = msg;
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
            int deli = index;
            //Give a service call to delete record and pass index/you can pass <id> in same manner.
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }

You can see that I am passing certain parameters to DeleteRecord() which is my Child window, well I am passing those from MainPage.xaml.cs, before looking at that, you can see from above code that you can freely use those Ok and Cancel button event and can implement whatever logic you want to. I am just declaring one variable i and some string, why I am using “i” is to prove that Data from MainPage.xaml.cs can be pass over here, So in reality you can pass Record’s “id” to do particular DML Operation.

To pass these values to this Child Windows you need to write following code in MainPage.xaml.cs like this :

private void btnDelete_Click(object sender, RoutedEventArgs e)
       {
           int i = dg.SelectedIndex;
           DeleteRecord del = new DeleteRecord("Record Deleting...", "Are you sure you want to Delete Record no." + i, i);
           del.Show();
       }

Where btnDelete is my Hyperlink button which I embeded in DataGrid’s template. I am making instance of DeleteRecord() which is nothing but my child window and passing selected record’s index along with message.It will look like this once you click on Delete link :

DelpopGrid

Once you click on either OK or Cancel, we have their respective events ready to handle. Similarly I did this for URL by passing url of video to a separate child window and embedded Media Element in it, so it looks like this :

VidpopGrid

So this is how you can even play video also from Grid, I know this may be a fast preview, but as I said in my previous articles, more is coming in future,So I am not going to stop on this example only, Soon I will be talking about actual CRUD operations with WCF and LINQ etc.

Hope this will help you to make use of DataGrid control in your Silverlight 3 projects/applications.

Vikram.

15 comments:

Swati said...

hi..
its really very useful..is it possible to use hyperlink button within datagrid b'coz i am using silverlight 2.0.

Vikram Pendse said...

Hi Swati,

Thanks for your comments. For Hyperlink,You can try with Data Template and put Hyperlink control in a same fashion like I did over here, you can set Navigate URL property for actual navigation from link and you can bind the content too.

The same query posted by one of user on Silverlight forums, I would like to tell you that,you also go through it once :

http://silverlight.net/themes/silverlight/forums/thread.aspx?ThreadID=63345

Let me know it it works for you.

Razia Sultana said...

Good Article. Please provide the source code.

Vikram Pendse said...

Hi Razia,

I guess source code is already there along with the post, if you find it difficult to grab, let me know,I can mail you the same.

usman said...

Hi Vikrm,

You have provided information with a gr8 elaboration, thanks for this.

I have an issue, and I spent hours on it, that is really pinching me even after working on ASP.Net for the past 1 year, may be I haven't
develop my taste for silver light.
Anyhow, I have a data grid and I am okay in binding it with my data source, but now i want to edit and get Rows of grid in a button's event handler that is on my form and not the part of grid's controls, could you please help me out of this scenario.

Thanks in an anticipation.

ahmer said...

thanks vikram for such a nice article i need to do a task entry grid as it is in ms project using silver light u must have seen that can u help me in this regard

ahmer said...

thanks vikram
i need to design a task entry grid as it is in msproject u must have seen that with indentation support most important..

nithin said...

hi vikram anna,
How to delete the record which is getting from database through WCF and binded with grid.I am doing a task on it.Pls help me...

anish patel said...

nice article...
I want to reorder the rows in datagird of silverlight3.Is it possible to do..????

Mathi said...

Hi, How to show the files of pdf or xls (attachment of that row) when they click a particulat row of hyperlink cell.

Mathi said...

Hi,

I've the hyperlink Datagrid Templatecolumn, I want to open the respective attachments of file(.pdf,.Xls,.doc) for that row when user click the hyperlink cell. How to do this. can anyone suggest?

Mathi said...

Hi,
I'm using Hyperlink Datagrid Template column and i want to show the attachments of file(.pdf,.xls,.doc) when user clicks the hyperlink cells of respective row.Can any one suggest how to do this option in silverlight 3 controls.

Ravi said...

Vikram,

good morning. thanks for a nice page. on your reply to Ms. Swati (May 2009), you had provided a forums link and that link is no longer working. using thread id info you had provided, i fished out the same thread:


http://forums.silverlight.net/forums/t/63345.aspx


thanks and keep up the good work.


regards
Ravi.

chekri said...

Vikram sir,
Your article is awesome, i am looking for similar stuff. In one approach i have got everything what i want. But i do have a doubt. In the above grid, how can we display images in any of the columns. Could you please update me at your earliest. Thank you.

chekri said...

Hello sir,
Its a great article. It helped me a lot, could you please help me on how to add images to any of the columns. It would be greatfull if you help me asap. Thanks in advane.