in

Matt’s Blog

April 2008 - Posts

  • Silverlight 2.0 Beta 1 DataGrid Sample

    At the recent MIX 08 conference, several new features were unveiled for SilverLight 2.  The DataGrid component is one of those new additions, which I recently decided to explore by building a simple SilverLight 2.0 application that loads an RSS feed into the new DataGrid.  This post will also illustrate calling a web service in SilverLight 2.0 Beta 1 and binding the DataGrid using LINQ with XML.

    If you decide to follow along with this example, you will need the following prerequisites:

    Once you have the above pre-requisites installed, create a new SilverLight project by going to File | New Project.  Select the Silverlight project type and the SilverLight application template as you see in the figure below.

     

     

     

     

    After you click OK, the "Add Silverlight Application" dialog will appear.  Select the radio button labeled "Add new Web to the solution for hosting the control", select the "Web site" project type, and Name the web  "SilverLightDataGridSample_Web".   See the figure below for a snapshot of this dialog after completing these steps:

     

     

    Once you have made all the selections as described above, click OK.  You should now see a blank canvas on your screen. 

     

    In order to use the DataGrid, you will need to add a reference to System.Windows.Controls.Data as seen below.

     

     

    This application will allow a user to enter an RSS feed URL into a text box and click a button to fill the DataGrid with data from the feed.  To accomplish this we will need to add a TextBox, a Button, and a DataGrid to the page (and a few controls to make it look pretty).   Here is the XAML to layout the interface:

     

    <UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverLightDataGridSample.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid x:Name="LayoutRoot" >

    <Grid.Background>

    <RadialGradientBrush Center=".1,.1" RadiusX="1" RadiusY="1">

    <GradientStop Color="DarkBlue" Offset=".1"/>

    <GradientStop Color="Aquamarine" Offset="1.5"/>

    </RadialGradientBrush>

    </Grid.Background>

    <Canvas>

    <Rectangle Fill="Black" Width="800" Height="600" Canvas.Top="105" Canvas.Left="205" Opacity="0.25">

    </Rectangle>

    <Border BorderThickness="1" BorderBrush="#BBBBBB" Opacity="1.0" Background="Silver" Width="800" Height="600" Canvas.Top="100" Canvas.Left="200">

    <StackPanel x:Name="stpMain" Margin="10 10 10 10">

    <TextBlock x:Name="tbURLLabel" Text="Feed Url" ></TextBlock>

    <TextBox x:Name="txtURL" BorderBrush="Black" Height="20" Width="300" HorizontalAlignment="Left" FontSize="12">

    </TextBox>

    <Button x:Name="btnFetch" Content="Fetch Data" ToolTip="Fetch" Height="20" Width="100" ClickMode="Press" Click="btnFetch_Click" HorizontalAlignment="Left" Margin="0 10 0 0" >

    </Button>

    <my:DataGrid x:Name="dgFeeds" AutoGenerateColumns="False" IsReadOnly="True" Height="450" Width="750" RowHeight="50" Visibility="Collapsed" HorizontalAlignment="Left" Margin="0 10 0 0" ColumnWidth="685" >

    <my:DataGrid.Columns>

    <my:DataGridTemplateColumn>

    <my:DataGridTemplateColumn.CellTemplate>

    <DataTemplate>

    <StackPanel Margin="5 5 5 5" Width="600">

    <TextBlock Text="{Binding Title}"/>

    <HyperlinkButton Content="View Post" NavigateUri="{Binding PostUri}" TargetName="_blank"></HyperlinkButton>

    </StackPanel>

    </DataTemplate>

    </my:DataGridTemplateColumn.CellTemplate>

    </my:DataGridTemplateColumn>

    </my:DataGrid.Columns>

    <my:DataGrid.RowDetailsTemplate>

    <DataTemplate>

    <StackPanel Margin="5 5 5 5" Width="600" Height="75" >

    <TextBlock Text="{Binding CleanedDescription}" TextWrapping="Wrap" Width="600" FontSize="10"/>

    </StackPanel>

    </DataTemplate>

    </my:DataGrid.RowDetailsTemplate>

    </my:DataGrid>

    </StackPanel>

    </Border>

    </Canvas>

    </Grid>

    </UserControl>

     

    Before compiling, you will also want to add an OnClick event to Page.xaml.cs that looks like this:

     

    private void btnFetch_Click(object sender, RoutedEventArgs e)

    {

    }

    We will add code to this method later.  At this point you should be able to run the application and see something that looks like this:

     

     

    Our next step is to bind our data grid to an RSS feed.  There is one challenge with this since SilverLight will only allow us to make cross domain requests if the server has a policy file defined.  Since we cannot assume there is a policy file for every url the user might enter, we will create a server side web service that will query the desired url and return the XML for the feed.   To accomplish this, add a new web service to the SilverLightDataGridSample_Web that is used for hosting the control,  call this web service RSS_Fetcher.   In RSS_Fetcher.cs located in the App_Code folder, add a web method like the following:

     

        [WebMethod]

        public string GetRSS(string Url)

        {

            try

            {

              

                XmlReader xr = XmlReader.Create(Url);           

                XmlDocument xmlDoc = new XmlDocument();

                xmlDoc.Load(xr);

             

                return xmlDoc.OuterXml.ToString();

            }

            catch (Exception exc)

            {

                return exc.Message;

            }       

        }

     

     

    This method will fetch the XML for the input url and return it back to our SilverLight control.  After adding the web service in the SilverLightDataGridSample_Web project, right click references in the SilverLightDataGridSample project and select Add Service Reference.   When the dialog appears, click Discover, select the RSS_Fetcher.asmx, and then enter RSS_Service for the namespace.  See the screen shot below:

     

     

     

    Once you click OK, the reference will be added.  Before we can finish wiring the web service results to the DataGrid, we need to create a class that will

    represent the post data in the RSS feed.   So create a new class in the SilverLightDataGridSample  called PostItem.cs, and add the following code to this class:

     

     

    using System;

    using System.Windows;

    using System.Windows.Controls;

    using System.Windows.Documents;

    using System.Windows.Ink;

    using System.Windows.Input;

    using System.Windows.Media;

    using System.Windows.Media.Animation;

    using System.Windows.Shapes;

    using System.Text.RegularExpressions;

     

    namespace SilverLightDataGridSample

    {

        public class PostItem

        {

            private string _title;

            private string _link;

            private string _description;

            private DateTime _pubdate;

     

            public string Title

            {

                get { return _title; }

                set { _title = value; }

            }       

           

     

            public string Link

            {

                get { return _link; }

                set { _link = value; }

            }      

           

     

            public string Description

            {

                get { return _description; }

                set { _description = value; }

            }

          

     

            public DateTime PubDate

            {

                get { return _pubdate; }

                set { _pubdate = value; }

            }

     

            public Uri PostUri

            {

                get

                {

                    return new Uri(Link);

                }

            }

     

            public string CleanedDescription

            {

                get

                {

                    string cleanedText = StripHTML(_description);

                    if (cleanedText.Length > 200)

                        cleanedText = cleanedText.Substring(0, 200);

     

                    return cleanedText;

                }

            }

     

            private string StripHTML(string HTML)

            {

                string ReturnString = "";

     

                // Replace all HTML tag matches with the empty string

                Regex thisExpression = new Regex("<(.|\n)+?>");

                ReturnString = thisExpression.Replace(HTML, "");

               

                ReturnString = ReturnString.Replace("&nbsp;", " ");

     

                return ReturnString;

            }      

                       

       

     

    }

     

     

    You will notice that this class is defining a few basic properties that are commonly found in an RSS feed.  You may also notice that the XAML posted

    earlier contains bindings to properties with the same names.   To complete our application we need to call the web service from the button click event, and bind the data to the DataGrid.

     

    To call the web service we will need to do two things.  The first is to add code to btnFetch_Click so that it looks like the following:

     

    private void btnFetch_Click(object sender, RoutedEventArgs e)

            {

                //determine what the URL of the service should be on our server

                string wsUrl = System.Windows.Browser.HtmlPage.Document.DocumentUri.AbsoluteUri;

                wsUrl = wsUrl.Substring(0, wsUrl.LastIndexOf('/') + 1) + "RSS_Fetcher.asmx";

     

     

                //create the binding and set the MaxReceivedMessageSize

                System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();

                binding.MaxReceivedMessageSize = int.MaxValue;  //Without this large feeds will throw an exception

     

                //instantiate and call the service

                RSS_Service.RSS_FetcherSoapClient rssSvc = new RSS_Service.RSS_FetcherSoapClient(binding, new System.ServiceModel.EndpointAddress(wsUrl));

                rssSvc.GetRSSCompleted += new EventHandler<RSS_Service.GetRSSCompletedEventArgs>(rssSvc_ServiceCompleted);

                rssSvc.GetRSSAsync(txtURL.Text);

            }

     

    To complete the web service wire up, add the following method to handle the GetRSSCompleted event.   You will also need to right click on References and

    in the SilverLightDataGridSample project and add a reference to System.Xml.Linq.

     

    void rssSvc_ServiceCompleted(object sender, RSS_Service.GetRSSCompletedEventArgs e)

            {

     

                System.Xml.Linq.XDocument rssFeed = System.Xml.Linq.XDocument.Parse(e.Result.ToString());

                var posts = from item in rssFeed.Descendants("item")

                            select new PostItem

                            {

                                Title = item.Element("title").Value,

                                Link  = item.Element("link").Value,

                                Description = item.Element("description").Value,

                                PubDate = Convert.ToDateTime(item.Element("pubDate").Value)

                            };

     

                dgFeeds.ItemsSource = posts;

                dgFeeds.Visibility = Visibility.Visible;

                dgFeeds.RowDetailsVisibility = DataGridRowDetailsVisibility.VisibleWhenSelected;          

               

            }

     

    You will notice in this method we create an instance of an Xdocument and use LINQ to select all "item" nodes into a list of items of type PostItem.

    Once we have the list of PostItem objects we can very easily bind it to the DataGrid by setting the ItemsSource property.

     

    Now if you compile and run the application, you should be able to enter an RSS feed link and click the button to populate the grid.  The results should look like the figure below:

     

     

     

     

    If we re-examine the XAML for the DataGrid we will see that the DataGridTemplate column renders the title and hyperlink on all rows and the RowDetailsTemplate renders the section that expands out each time we select a row.   From this example we have illustrated how to call a web service from SilverLight 2.0 Beta 1,  and how to bind a data grid from XML data using LINQ.

     

     

     

     

     

Powered by Community Server (Commercial Edition), by Telligent Systems