500 likes | 627 Views
Using LINQ to read structured data. Pongsakorn Poosankam. Microsoft Innovation Center Manager. Microsoft (Thailand ) Limited. Topics. Structured data and LINQ Databases and objects Database queries and LINQ Creating Silverlight layout templates Databinding to lists
E N D
Using LINQ to read structured data Pongsakorn Poosankam Microsoft Innovation Center Manager Microsoft (Thailand) Limited
Topics • Structured data and LINQ • Databases and objects • Database queries and LINQ • Creating Silverlight layout templates • Databinding to lists • Using LINQ queries to produce object collections
Reading Twitter XML feeds • We can use a WebClient request to read structured data from a web host • The Twitter feed information can be supplied as an XML structured data file • Our program must pull out some content and display it
Reading the Twitter feed • This code will fetch the XML that describes a Twitter feed • The URL contains the Twitter username privatevoidloadButton_Click(object sender, RoutedEventArgs e){stringurl = "http://twitter.com/statuses/user_timeline/" +nameTextBox.Text + ".xml";client.DownloadStringAsync(newUri(url));}
XML structured data • We have already seen XML in the markup language used by Silverlight to describe pages • The XML for a Twitter feed contains elements and properties which are formatted to describe Twitter post information • We could write some C# to decode the feed, but we are going to use LINQ instead • LINQ stands for Language INtegrated Query
LINQ • LINQ is a technology that is part of the .NET system libraries • It builds on C# language features to provide easy data transfer between structured data storage and the object models used by modern languages • It is well worth knowing about
A diversion into databases • If you want to store large amounts of structured data you will not write a system to do this • Instead you will use a database • The database manages the data for you, and your program will send commands to it to add, remove and search for data
A simple Database • We can start by considering a simple sales database • This is the customer table • Each row describes a single customer
Two other tables Sales table Product Table
Using the database • We can combine the information in the tables to obtain transaction details • Rob has Customer ID 123456 • Customer ID 123456 ordered product ID1001 • 1001 is the product ID of a Windows Phone • Rob bought a Windows Phone • We get the database to do this for us by issuing queries to it
Database queries • This SQL query will create a table that contains all the orders placed by Rob • This result can then be used as the basis of another query • Database queries are much easier to create than the equivalent program statements to work through the data SELECT * FROM Orders WHERE CustomerID = "123456"
A C# sales database • If we wrote a C# program to store the sales database our starting point would be class designs • The above class holds Customer information publicclassCustomer{publicstring Name {get; set;}publicstring Address { get; set; }stringBankDetails { get; set; }publicint ID { get; set; }}
Holding multiple Customers • Once we have a class that contains the required data we can create collections of that object • Above we have created a list of customers • We can then store customers in the list by adding them to it List<Customer> Customers = newList<Customer>();
Searching for customers publicList<Order> FindCustomerOrders(intCustomerID){List<Order> result = newList<Order>();foreach ( Orderorderin Orders ) {if (order.CustomerID == CustomerID) {result.Add(order); } }return result;} • This is the C# code that implements the SQL query we saw earlier
Databases and objects • If object-oriented programs and databases are to work together we need something to convert from database tables to objects and back • We can do this by creating of “glue” code that creates objects and stores them back in tables • However, this task is made much easier by LINQ
A LINQ query varorderQueryResult =from order indb.Orderswhereorder.CustomerID == "123456"select order; • This is the LINQ code that implements the SQL query we saw earlier • It does not look like legal program statements, but it compiles perfectly • It is worth a closer look
Query result varorderQueryResult=from order indb.Orderswhereorder.CustomerID == "123456"select order; • The query returns a result which is given the type var • var means “a type which works here” • The type of a var variable depends on the context of the declaration • In this case orderQueryResult will hold a collection of var objects that look like orders
Iteration source varorderQueryResult=from order indb.Orderswhereorder.CustomerID == "123456"select order; • This sets up the iteration through the elements in a table • The db variable represents the database connection and we are using the Orders table from that database
Restriction operation varorderQueryResult=from order indb.Orderswhereorder.CustomerID == "123456"select order; • This is the restriction operation that identifies the orders to be selected from the table • In this case we are looking for orders with the CustomerID of 123456
Selection operation varorderQueryResult=from order indb.Orderswhereorder.CustomerID == "123456"select order; • This identifies the item to be selected and added to the result when the restriction operation succeeds • This means that we will get a collection of var results that look like order objects • We can then use these objects in our program
Databases on Windows Phone • LINQ is a great way to combine object oriented code and databases • Unfortunately the present version of Windows Phone does not have database support • But it does contain the LINQ libraries • This would seem a strange design choice • Fortunately LINQ can also be used to read structured data and create objects from it
Twitter XML <?xmlversion="1.0"encoding="UTF-8"?><statusestype="array"><status> <created_at>Tue Oct 12 11:57:37 +0000 2010</created_at><text> Hello from Twitter.</text><user> <id>2479801</id> <name>Rob Miles</name><profile_background_image_url> http://s.twimg.com/a/1286/images/themes/theme1/bg.png</profile_background_image_url></user></status></statuses> • This is an abridged Twitter status XML file
Performing the query XElementTwitterElement = XElement.Parse(twitterText); • The first thing we need to do is get LINQ to create a LINQ XML element or XElement • We will be able to perform LINQ operations on the XElement value as if it was a database source • The Parse method works through the XML data string returned by the server
Creating the display objects • We now have an easy way that we can use LINQ to pull the required data out of the XML feed • We want to obtain and display • The text of the Twitter post • The data of the post • The image of the Twitter user • Once we have these values we need to display them
Creating a display class publicclassTwitterPost{publicstringPostText { get; set; }publicstringDatePosted { get; set; }publicstringUserImage { get; set; }} • This the class that we will actually use to display a post on the screen • We will use Silverlight data binding to connect these properties to display elements
Using LINQ to create the display varpostList = from tweet intwitterElements.Descendants("status")selectnewTwitterPost{UserImage = tweet.Element("user"). Element("profile_image_url").Value,PostText = tweet.Element("text").Value,DatePosted = tweet.Element("created_at").Value}; • This is the LINQ query that will work through the status elements in the XML and create new TwitterPost instances from each status entry
Using LINQ to create the display varpostList = from tweet intwitterElements.Descendants("status")selectnewTwitterPost{UserImage = tweet.Element("user"). Element("profile_image_url").Value,PostText = tweet.Element("text").Value,DatePosted = tweet.Element("created_at").Value}; • There is no restriction part as we want all the status elements • We could add one if we wanted to select particular ones based on a criteria
Finding XML elements varpostList = from tweet intwitterElements.Descendants("status")selectnewTwitterPost{UserImage = tweet.Element("user"). Element("profile_image_url").Value,PostText = tweet.Element("text").Value,DatePosted = tweet.Element("created_at").Value}; • The Element method locates an element with a particular name • It can be used on the element it returns • This is how we get the profile image
The postList variable • The postList variable is a var type • This means that it will be set to the result of an operation that will build the type when it is used • In fact postList refers to a list of TwitterPost values • Now we need to get that list onto the Phone display
XAML templates • What we really want to do is bind our list of Twitter posts to some kind of list on the phone • It turns out that this is very easy to do • We can create a list template that describes the layout of some Silverlight elements that can be bound to properties in the TwitterPost class
What the display will look like • I want each twitter post to look like this • A picture on the left hand side, with the post date and content arranged to the right of this • We can use the Silverlight StackPanel element to lay this out for us
Outer StackPanel • The outer stack panel lays out elements across the list element <StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel>
Horizontal Stack Panel • There are two elements in the horizontal stack panel • One is the image of the Twitter user • The other will contain the date and the post text
User Image • This is the image of the Twitter user • The source property gives the url of the image to be displayed <StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel>
Post details • The second element is another Stack Panel • This contains the post date above the post text <StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel>
Post details • This is the date posted element • It binds to the DatePosted property in a TwitterPost value <StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel>
Post text • This is the post text itself • This is set to wrap around the text area <StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel>
StackPanel • A StackPanel will automatically arrange the items that are placed within it • We have seen that we can place one StackPanel value inside another • They allow you to create layouts that position themselves automatically
The Complete ListBox template <ListBox Height="442"HorizontalAlignment="Left" Name="tweetsListBox"VerticalAlignment="Top" Width="468"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox>
A ListBox display template <ListBox Height="442"HorizontalAlignment="Left" Name="tweetsListBox"VerticalAlignment="Top" Width="468"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox> The ListBox is called tweetsListbox
A ListBox display template <ListBox Height="442"HorizontalAlignment="Left" Name="tweetsListBox"VerticalAlignment="Top" Width="468"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox> It contains an item template for each list item the box is going to display
A ListBox display template <ListBox Height="442"HorizontalAlignment="Left" Name="tweetsListBox"VerticalAlignment="Top" Width="468"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal" Height="132"><Image Source="{BindingUserImage}" Height="73" Width="73" VerticalAlignment="Top"/><StackPanel Width="370"><TextBlock Text="{BindingDatePosted}"Foreground="#FFC8AB14"FontSize="22" /><TextBlock Text="{BindingPostText}"TextWrapping="Wrap"FontSize="24" /></StackPanel></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox> This is the StackPanel we created earlier
Putting it all together • Now we have a ListBox template for the dislay that will lay out the tweets the way that we want them to appear • The next thing is to connect the ListBox to a datasource that contains a collection of TwitterPost objects for display • First we can take a look at how such a list could be made
Displaying Lists of Tweets TwitterPost p1 = newTwitterPost{DatePosted = "Tue Oct 12 11:57:37 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is a test post from Rob"};TwitterPost p2 = newTwitterPost{DatePosted = "Wed Oct 13 14:21:04 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is another test post from Rob"};List<TwitterPost> posts = newList<TwitterPost>();posts.Add(p1);posts.Add(p2);
Displaying Lists of Tweets TwitterPost p1 = newTwitterPost{DatePosted = "Tue Oct 12 11:57:37 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is a test post from Rob"};TwitterPost p2 = newTwitterPost{DatePosted = "Wed Oct 13 14:21:04 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is another test post from Rob"};List<TwitterPost> posts = newList<TwitterPost>();posts.Add(p1);posts.Add(p2); This code creates two TwitterPost instances
Displaying Lists of Tweets TwitterPost p1 = newTwitterPost{DatePosted = "Tue Oct 12 11:57:37 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is a test post from Rob"};TwitterPost p2 = newTwitterPost{DatePosted = "Wed Oct 13 14:21:04 +0000 2010",UserImage= http://a3.twimg.com/1501/me2_normal.jpg",PostText = "This is another test post from Rob"};List<TwitterPost> posts = newList<TwitterPost>();posts.Add(p1);posts.Add(p2); These are then added to a list of posts
Binding an XML data source tweetsListBox.ItemsSource = posts; • This sets the ItemSource property of the tweetsListBox to the collection of posts that we just created • Data binding will do the rest for us
Binding to the twitter data tweetsListBox.ItemsSource = postList; • To see the posts loaded from the Twitter feed we use the list created by the LINQ query • The list will expand to fill the display and provide scrolling support if you want to view the rest of the items
Demo Demo 1: Twitter viewer
Review • Web requests can return structured data in XML format • The Language Integrated Query (LINQ) tools provide a way of converting structured data into objects • LINQ can decode an XML document and create objects with data properties • Collections of objects can be bound to Silverlight lists which contain display templates