Max's Blog

.NET, SQL Server and other exciting stuff

  Home  |   Contact  |   Syndication    |   Login
  19 Posts | 1 Stories | 13 Comments | 0 Trackbacks

News

Tag Cloud


Archives

Post Categories

Links

Monday, January 30, 2012 #

I am happy to announce that I have open sourced and released my first Windows Phone 7 Application to Marketplace a few days back. You can get the source code from http://gtasksplus.codeplex.com/. I will also do a series of few blog posts to take you all through developing the application from scratch. Check back regularly.

Sorry for not posting anything for a long time, I have been concentrating on learning some new things and did not really get a chance to continue blogging. Will try and be consistent here after.

Thanks

Max


Wednesday, December 08, 2010 #

Part 1 - Listing Data from Database:

Let us now learn ASP.NET MVC 2 from Scratch by actually developing a front end website for the Chinook database, which is an alternative to the traditional Northwind database. You can get the Chinook database from here. As always the best way to learn something is by working on it and doing something. The Chinook database has the following schema, a quick look will help us implementing the application in a efficient way.

Let us first implement a grid view table with the list of Employees with some details, this table also has the Details, Edit and Delete buttons on it to do some operations. This is series of post will concentrate on creating a simple CRUD front end for Chinook DB using ASP.NET MVC 2.

In this post, we will look at listing all the possible Employees in the database in a tabular format, from which, we can then edit and delete them as required. In this post, we will concentrate on setting up our environment and then just designing a page to show a tabular information from the database.

We need to first setup the SQL Server database, you can download the required version and then set it up in your localhost. Then we need to add the LINQ to SQL Classes required for us to enable interaction with our database.

Linqtosqlclasses

Now after you do the above step, just use your Server Explorer in VS 2010 to actually navigate to the database, expand the tables node and then drag drop all the tables onto the Object Relational Designer space and you go you will have the tables visualized as classes.

ORD

As simple as that.

Chinook Classes

Now for the purpose of displaying the data from Employee in a table, we will show only the EmployeeID, Firstname and lastname. So let us create a class to hold this information. So let us add a new class called EmployeeList to the ViewModels. We will send this data model to the View and this can be displayed in the page.

public class EmployeeList
{
   public int EmployeeID { get; set; }
   public string Firstname { get; set; }
   public string Lastname { get; set; }
   public EmployeeList(int empID, string fname, string lname)
   {
      this.EmployeeID = empID; this.Firstname = fname; this.Lastname = lname;
   }
}

Ok now we have got the backend ready. Let us now look at the front end view now. We will first create a master called Site.Master and reuse it across the site. The Site.Master content will be

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="ChinookMvcSample.Views.Shared.Site" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <style type="text/css">
        html
        {
            background-color: gray;
        }
        .content
        {
            width: 880px;
            position: relative;
            background-color: #ffffff;
            min-width: 880px;
            min-height: 800px;
            float: inherit;
            text-align: justify;
        }
    </style>
    <script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <center>
        <h1>
            My Website</h1>
        <div class="content">
            <asp:ContentPlaceHolder ID="body" runat="server">
            </asp:ContentPlaceHolder>
        </div>
    </center>
</body>
</html>

The backend Site.Master.cs does not contain anything. In the actual Index.aspx view, we add the code to simply iterate through the collection of EmployeeList that was sent to the View via the Controller. So in the top of the Index.aspx view, we have this inherits which says

Inherits="System.Web.Mvc.ViewPage<IEnumerable<ChinookMvcSample.ViewModels.EmployeeList>>"

In this above line, we dictate that the page is consuming a IEnumerable collection of EmployeeList. So once we specify this and compile the project. Then in our Index.aspx page, we can consume the EmployeeList object and access all its methods and properties.

<table class="styled" cellpadding="3" border="0" cellspacing="0">
    <tr>
        <th colspan="3">
        </th>
        <th>
            First Name
        </th>
        <th>
            Last Name
        </th>
    </tr>
    <% foreach (var item in Model)
       { %>
    <tr>
        <td align="center">
            <%: Html.ActionLink("Edit", "Edit", new { id = item.EmployeeID }, new { id = "links" })%>
        </td>
        <td align="center">
            <%: Html.ActionLink("Details", "Details", new { id = item.EmployeeID }, new { id = "links" })%>
        </td>
        <td align="center">
            <%: Html.ActionLink("Delete", "Delete", new { id = item.EmployeeID }, new { id = "links" })%>
        </td>
        <td>
            <%: item.Firstname %>
        </td>
        <td>
            <%: item.Lastname %>
        </td>
    </tr>
    <% } %>
    <tr>
        <td colspan="5">
            <%: Html.ActionLink("Create New", "Create") %>
        </td>
    </tr>
</table>

The Html.ActionLink is a Html Helper to a create a hyperlink in the page, in the one we have used, the first parameter is the text that is to be used for the hyperlink, second one is the action name, third one is the parameter to be passed, last one is the attributes to be added while the hyperlink is rendered in the page. Here we are adding the id=”links” to the hyperlinks that is created in the page.

In the index.aspx page, we add some jQuery stuff add alternate row colours and highlight colours for rows on mouse over.

Employee List page

Now the Controller that handles the requests and directs the request to the right view. For the index view, the controller would be

public ActionResult Index()
{
    //var Employees = from e in data.Employees select new EmployeeList(e.EmployeeId,e.FirstName,e.LastName);
    //return View(Employees.ToList());
    return View(_data.Employees.Select(p => new EmployeeList(p.EmployeeId, p.FirstName, p.LastName)));
}

Let us also write a unit test using NUnit for the above, just testing EmployeeController’s Index.

DataClasses1DataContext _data;
public EmployeeControllerTest()
{
    _data = new DataClasses1DataContext("Data Source=(local);Initial Catalog=Chinook;Integrated Security=True");
}
 
[Test]
public void TestEmployeeIndex()
{
    var e = new EmployeeController(_data);
    var result = e.Index() as ViewResult;
    var employeeList = result.ViewData.Model;
    Assert.IsNotNull(employeeList, "Result is null.");
}

In the first EmployeeControllerTest constructor, we set the data context to be used while running the tests. And then in the actual test, We just ensure that the View results returned by Index is not null.

Here is the zip of the entire solution files until this point. Let me know if you have any doubts or clarifications.

Cheers! Have a nice day.


Sunday, July 25, 2010 #

First of all, sorry for not posting for a quite long time. I have started working on designing and developing a charity website for blood donation. So all my leisure time was diverted into that. I will ensure that going forward, I post at least one post every week. Lets get into the topic of this week, without delaying any more time.

I have always been using asp:Menu and asp:Treeview for transforming the sitemaps to super cool menu which are auto generated by ASP.NET for us. But I wanted more and thought some jQuery can solve this. So the ultimate deal is to loop through the sitemap and add our own extra bits to it to render it as a menu and use jQuery for adding some animation. Seriously jQuery is powerful, I would have ended up writing whole lots of Javascript code for doing a small animation, which is ridiculously one line in jQuery. I attended Microsoft WebCamps in Sydney and that inspired me to move towards jQuery from Javascript. I had a great time there learning new stuff.

This is how the menu will look like.

Menu


 

By default only the Level 1 will be shown and when you click on it, the next level will open up. Also based on the collapsible state, the arrow image will be reversed automatically. Also the current page’s link will be shown by default. I have tested it and its working fine in IE 6,7,8 and Firefox and Chrome browsers. I initially used ul, li combos but that did not work fine in IE 7 & 6, so had to follow the div route. As such this supports 4 levels of link hierarchy, but can easily be modified to handle any number of levels.

Now the steps. I believe you have your own Sitemap, else you can use the dummy Sitemap I’ve used in this sample. You can get the files here.

1) The basic idea is to render the sitemap links within div tags and put in a class name based on the level it is in like menu1, menu2, etc…

2) For example, the DataToolBox link and its sub links are rendered as follows in the browser using IE8 using this method.

<DIV class="Menu1 linky linkyup" title="DataToolBox controls">&nbsp;DataToolBox</DIV>
<DIV>
    <DIV style="DISPLAY: block" class=Menu2 title="ListView Example"><A href="/ListViewExample.aspx">ListView</A></DIV>
    <DIV style="DISPLAY: block" class=Menu2 title="GridView Example"><A href="/GridViewExample.aspx">GridView</A></DIV>
    <DIV style="DISPLAY: block" class="Menu2 linky linkyup" title="DataToolBox controls">&nbsp;DataToolBox</DIV>
    <DIV>
        <DIV style="DISPLAY: block" class=Menu3 title="ListView Example"><A href="/ListViewExample1.aspx">ListView</A></DIV>
        <DIV style="DISPLAY: block" class=Menu3 title="GridView Example"><A href="/GridViewExample1.aspx">GridView</A></DIV>
        <DIV style="DISPLAY: block" class="Menu3 linky linkyup" title="DataToolBox controls">&nbsp;Testing</DIV>
        <DIV>
            <DIV style="DISPLAY: block" class=Menu4 title="ListView Example"><A href="/TestingExample1.aspx">ListView</A></DIV>
        </DIV>
    </DIV>
</DIV>

3) Now we will create the main method which will, render the menu snippet on to the front end. For this, we create a literal control named menu in the aspx page. We will set the text of this literal control to the html generated by our method.

<asp:Literal runat="server" ID="menu"></asp:Literal>

4) Method for generating the menu code. We encapsulate the menu within a plain div only for levels higher than 1. In some cases, you will have a sitemap entry but would not want to render it, in that case, add a visible attribute to the sitemapnode and set it as false and render only those nodes which does not have a visible attribute or the ones with visible as true. I just then build a string and loop through the siblings for rendering them as well and if that nodes has any children, then I increment the level and call the same method recursively.

    public void getChildren(SiteMapNode n, int Level)
    {
        if (Level > 1)
            menu.Text += "<div>";
        while (true)
        {
            if (n["Visible"] == null)
            {
                // Displays the title of each node.
                if (n.Url.Contains(".aspx"))
                {
                    menu.Text += "<div class=\"Menu" + Level.ToString() + "\" title=\"" + n.Description + "\"";
                    menu.Text += "><a href=\"" + n.Url + "\">" + n.Title + "</a></div>";
                }
                else
                {
                    menu.Text += "<div class=\"Menu" + Level.ToString() + " linky\"";
                    menu.Text += " title=\"" + n.Description + "\">&nbsp;" + n.Title + "</div>";
                    if (n.ChildNodes.Count > 0)
                    {
                        Level++;
                        getChildren(n.ChildNodes[0], Level);
                        Level--;
                    }
                }
            }
            if (n.NextSibling == null)
                break;
            else
                n = n.NextSibling;
        }
        if (Level > 1)
            menu.Text += "</div>";
    }
}

5) You then need to add a script reference to jQuery library 1.4.2 to one of Microsoft or Google CDN

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js” language="javascript" type="text/javascript"></script>

6) Then I add this jQuery snippet to the end of the aspx page within a <script> tag. Now here, I hide all the menus higher than 1 by default. And add some click functionality to each level menu to toggle open the next level below it, also a few lines to close all the sub menus when clicked on higher level. Like closing the level 3 and level 4 menus when I click on level 1 to close it. Also I’ve used the toggleClass to change the arrow image. Believe me, jQuery is the way forward!! I can’t imagine writing all these in Javascript.

$(document).ready(function () {
    $('div.Menu1.linky').next('div').children('div.Menu2').hide();
    $('div.Menu2.linky').next('div').children('div.Menu3').hide();
    $('div.Menu3.linky').next('div').children('div.Menu4').hide();

    $("div.Menu1.linky").click(function () {
        $(this).next('div').find('div.Menu3').hide();
        $(this).next('div').find('div.Menu4').hide();
        $(this).next('div').children('div.Menu2').toggle();

        $(this).toggleClass('linkyup');
        $(this).next('div').find('div.Menu2').removeClass('linkyup');
        $(this).next('div').find('div.Menu3').removeClass('linkyup');
    });

    $("div.Menu2.linky").click(function () {
        $(this).next('div').find('div.Menu4').hide();
        $(this).next('div').children('div.Menu3').toggle();

        $(this).toggleClass('linkyup');
        $(this).next('div').find('div.Menu4').removeClass('linkyup');
        $(this).next('div').children('div.Menu3').removeClass('linkyup');
    });

    $("div.Menu3.linky").click(function () {
        $(this).next('div').children('div.Menu4').toggle();
        $(this).toggleClass('linkyup');
    });

});

7) Another problem here I had is to maintain the same current page’s link opened during post back. So what I do here is, have a hidden field in the page and then it was my friend Suprotim Agarwal an ASP.NET MVP who came to the rescue. This particular aspect was inspired by an article in DonetCurry by him. Here it is for your reference. Also this one. My many thanks to him. So I store the current page’s url in a hidden field and and find out the a tag with this url and make it parent level menus in open state. It also works when there is some query string that is appended to the url.

So add this to the current page aspx.

<asp:HiddenField Value="" ID="CurrentPageTitle" runat="server" />

8) So now the jQuery which handles the toggling based on the current page’s url that is saved in the above hidden field.

//If current URL is in Level 4.
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').parent('div').parent('div').children().show();
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').parent('div').children().show();
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').children().show();

$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').parent('div').parent('div').prev('div.Menu1').toggleClass('linkyup');
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').parent('div').prev('div.Menu2').toggleClass('linkyup');
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu4').parent('div').prev('div.Menu3').toggleClass('linkyup');

//If current URL is in Level 3.
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu3').parent('div').parent('div').parent('div').children().show();
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu3').parent('div').parent('div').children().show();
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu3').parent('div').children().show();

$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu3').parent('div').prev('div.Menu2').toggleClass('linkyup');
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu3').parent('div').parent('div').prev('div.Menu1').toggleClass('linkyup');

//If current URL is in Level 2.
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu2').parent('div').parent('div').children().show();
$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu2').parent('div').children().show();

$("a[href*='<%=CurrentPageTitle.Value%>']").parent('div.Menu2').parent('div').prev('div.Menu1').toggleClass('linkyup');

9) Also add this line to the page load event, which sets the current page url to the hidden field.

CurrentPageTitle.Value = Request.ServerVariables["URL"].Replace("/", \\/);

10) Download the files and try navigating to the TestingExample1.aspx file and you will see that the levels are automatically shown visible for us. Also try putting some query string values.

11) Get the files here.

Please comment below or contact me for any clarifications / issues. I will be very happy to help you out with all what I can.

Cheers!


Tuesday, May 18, 2010 #

Great Websites for everyday tips and tricks
http://www.lifehack.org/ - Tips & Tricks to hack your life.
http://www.lifehacker.com/ - Great tips and tricks for life and computers
http://www.nirmaltv.com/ - Good blog by a Windows MVP concentrating on Windows tips & tricks. 
http://www.neowin.net/ - Good blog that summarizes the tech world happenings.
http://techcrunch.com/ - Blog concentrating on the internal happenings for big companies
 
Inspirational Stuff
http://sourcesofinsight.com/ - Insipration articles relating to management, etc...
http://www.pravsworld.com/ - Wonderful quotes with images to inspire you everyday.
http://www.dumblittleman.com/
http://www.lifehack.org/
 
.NET Technology Stuff
http://blog.cwa.me.uk/ - The Morning brew blog which summarizes the happening in Microsoft related technology world for that day.
http://weblogs.asp.net/scottgu/ - Blog of legendary Scott Gutherie from Microsoft.
http://www.hanselman.com/blog/ - Blog of legendary Scott Hanselman from Microsoft.
http://sqlquthority.com/ - Blog by Pinal Dave, a SQL Server MVP for any information regarding SQL Server.
http://www.dotnetcurry.com/ - Blog by Suprotim Agarwal, a ASP.NET MVP for a fantastic articles on .Net 
 
Downloads
http://filehippo.com - Releases the latest versions of many great softwares as when a new version is released, great website to keep your softwares updated all the time.
http://download.com - Great website for downloading softwares.
http://www.microsoft.com/downloads/en/default.aspx - I always check on to the latest downloads in Microsoft.
 
Webdesign
http://www.smashingmagazine.com/ - Great website that focuses mainly on the UX / Web Design stuff.
http://www.smashingapps.com/ - Another website that focuses on various apps that could make our life more easier, informative.
 
Others
http://www.microsoft.com - I love Microsoft and always check their homepage time to time.
http://cricinfo.com - I love cricket and want to keep up myself with the happenings.
http://www.google.com - ?
http://www.bing.com - ?
 
Follow me @maxonweb and also my hand picked lists for more specific updates.
 
Book mark this page - http://maxblogson.net/archive/2010/05/18/followwebsites.aspx, I will keep updating this as when I find more interesting websites.

Cheers!


Thursday, April 29, 2010 #

Download this article as a PDF

Welcome back :) This week we are going to look at something more exciting and a much required feature for any twitter client – auto refresh so as to show new status updates. We are going to achieve this using Silverlight 4 Timers and a bit and refresh our datagrid every 2 minutes to show new updates. We will do this so that we do only minimal request to the twitter api, so that twitter does not block us – there is a limit of 150 request an hour. Let us get started now. Also we will get the profile user id hyperlinked, so that when ever the user click on it, we will take them to their twitter page.

Also it was a pain to always run this application by pressing F5, then it would open in a browser you would have to right click uninstall and install it again to see any changes. All this and yet we were not able to debug it :( Now there is a solution for this to run a silverlight application directly out of browser and yet have the debug feature. Super cool, here is how.

Right on the Silverlight project and go to debug and then select the Out-Of-Browser application option and choose the *.Web project.

image

Then just right click on the SL project and set as Startup Project. There you go, now every time you press F5, it will automatically run out of browser and still have the debug options. I go to know about this after some binging.

Now let us jump to the core straight away.

1) To get the user id hyperlinked, we need to have a DataGridTemplateColumn and within that have a HyperLinkButton. The code for this will  be

<data:DataGridTemplateColumn>
    <data:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <HyperlinkButton Click="HyperlinkButton_Click" Content="{Binding UserName}" TargetName="_blank" ></HyperlinkButton>
        </DataTemplate>
    </data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>

 

2) Now let us look at how we are getting this done by looking into HyperlinkButton_Click event handler. There we will dynamically set the NavigateUri to the twitter page. I tried to do this using some binding, eval like stuff as in ASP.NET, but no luck!

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    HyperlinkButton hb = (HyperlinkButton)e.OriginalSource;
    hb.NavigateUri = new Uri("http://twitter.com/" + hb.Content.ToString(), UriKind.Absolute);
}

3) Now we need to switch on our Timer right in the OnNavigated to event on our SL page. So we need to modify our OnNavigated event to some thing like below:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    image1.Source = new BitmapImage(new Uri(GlobalVariable.profileImage, UriKind.Absolute));
    this.Title = GlobalVariable.getUserName() + " - Home";
    if (!GlobalVariable.isLoggedin())
        this.NavigationService.Navigate(new Uri("/Login", UriKind.Relative));
    else
    {
        currentGrid = "Timeline-Grid";
        TwitterCredentialsSubmit();
        myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 60, 0);
        myDispatcherTimer.Tick += new EventHandler(Each_Tick);
        myDispatcherTimer.Start();
    }
}

I use a global string – here it is currentGrid variable to indicate what is bound in the datagrid so that after every timer tick, I can rebind the latest data to it again. Like I will only rebind the friends timeline again if the data grid currently holds it and I’ll only rebind the respective list status again in the data grid, if already a list status is bound to the data grid.

In the above timer code, its set to trigger the Each_Tick event handler every 1 minute (60 seconds). TimeSpan takes in (days, hours, minutes, seconds, milliseconds).

4) Now we need to set the list name in the currentGrid variable when a list button is clicked. So add the code line below to the list button event handler

currentGrid = currentList = b.Content.ToString();

5) Now let us see how Each_Tick event handler is implemented.

public void Each_Tick(object o, EventArgs sender)
{
    if (!currentGrid.Equals("Timeline-Grid"))
        getListStatuses(currentGrid);
    else
    {
        WebRequest.RegisterPrefix("https://", System.Net.Browser.WebRequestCreator.ClientHttp);
        WebClient myService = new WebClient();
        myService.AllowReadStreamBuffering = true;
        myService.UseDefaultCredentials = false;
        myService.Credentials = new NetworkCredential(GlobalVariable.getUserName(), GlobalVariable.getPassword());
        myService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimelineRequestCompleted);
        myService.DownloadStringAsync(new Uri("https://twitter.com/statuses/friends_timeline.xml"));
    }
}

If the data grid hold friends timeline, I just use the same bit of code we had already to bind the friends timeline to the data grid. Copy Paste.

But if it is some list timeline that is bound in the datagrid, I then call the getListStatus method with the currentGrid string which will actually be holding the list name.

6) I wanted to make the hyperlinks inside the status message as hyperlinks and when the user clicks on it, we can then open that link. I tried using a convertor and using a regex to recognize a url and wrap it up with a href, but that is not gonna work in silverlight textblock :( Anyways that convertor code is in the zip file.

7) You can get the complete project files from here.

8) Please comment below for your doubts, suggestions, improvements. I will try to reply as early as possible. Thanks for all your support.

 


Saturday, March 27, 2010 #

In this post, we are going to look into implementing lists into our twitter application and also about enhancing the data grid to display the status messages in a pleasing way with the profile images. Twitter lists are really cool feature that they recently added, I love them and I’ve quite a few lists setup one for DOTNET gurus, SQL Server gurus and one for a few celebrities. You can follow them here. Now let us move onto our tutorial.

1) Lists can be subscribed to in two ways, one can be user’s own lists, which he has created and another one is the lists that the user is following. Like for example, I’ve created 3 lists myself and I am following 1 other lists created by another user. Both of them cannot be fetched in the same api call, its a two step process.

2) In the TwitterCredentialsSubmit method we’ve in Home.xaml.cs, let us do the first api call to get the lists that the user has created. For this the call has to be made to https://twitter.com/<TwitterUsername>/lists.xml. The API reference is available here.

myService1.AllowReadStreamBuffering = true;
myService1.UseDefaultCredentials = false;
myService1.Credentials = new NetworkCredential(GlobalVariable.getUserName(), GlobalVariable.getPassword());
myService1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ListsRequestCompleted);
myService1.DownloadStringAsync(new Uri("https://twitter.com/" + GlobalVariable.getUserName() + "/lists.xml"));

3) Now let us look at implementing the event handler – ListRequestCompleted for this.

public void ListsRequestCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
{
    if (e.Error != null)
    {
        StatusMessage.Text = "This application must be installed first.";
        parseXML("");
    }
    else
    {
        //MessageBox.Show(e.Result.ToString());
        parseXMLLists(e.Result.ToString());
    }
}

 

4) Now let us look at the parseXMLLists in detail

xdoc = XDocument.Parse(text);
var answer = (from status in xdoc.Descendants("list")
              select status.Element("name").Value);
foreach (var p in answer)
{
    Border bord = new Border();
    bord.CornerRadius = new CornerRadius(10, 10, 10, 10);
    Button b = new Button();
    b.MinWidth = 70;
    b.Background = new SolidColorBrush(Colors.Black);
    b.Foreground = new SolidColorBrush(Colors.Black);
    //b.Width = 70;
    b.Height = 25;
    b.Click += new RoutedEventHandler(b_Click);
    b.Content = p.ToString();
    bord.Child = b;
    TwitterListStack.Children.Add(bord);
}

 

So here what am I doing, I am just dynamically creating a button for each of the lists and put them within a StackPanel and for each of these buttons, I am creating a event handler b_Click which will be fired on button click. We will look into this method in detail soon. For now let us get the buttons displayed.

5) Now the user might have some lists to which he has subscribed to. We need to create a button for these as well. In the end of TwitterCredentialsSubmit method, we need to make a call to http://api.twitter.com/1/<TwitterUsername>/lists/subscriptions.xml. Reference is available here. The code will look like this below.

myService2.AllowReadStreamBuffering = true;
myService2.UseDefaultCredentials = false;
myService2.Credentials = new NetworkCredential(GlobalVariable.getUserName(), GlobalVariable.getPassword());
myService2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ListsSubsRequestCompleted);
myService2.DownloadStringAsync(new Uri("http://api.twitter.com/1/" + GlobalVariable.getUserName() + "/lists/subscriptions.xml"));

6) In the event handler – ListsSubsRequestCompleted, we need to parse through the xml string and create a button for each of the lists subscribed, let us see how. I’ve taken only the “full_name”, you can choose what you want, refer the documentation here. Note the point that the full_name will have @<UserName>/<ListName> format – this will be useful very soon.

xdoc = XDocument.Parse(text);
var answer = (from status in xdoc.Descendants("list")
              select status.Element("full_name").Value);
foreach (var p in answer)
{
    Border bord = new Border();
    bord.CornerRadius = new CornerRadius(10, 10, 10, 10);
    Button b = new Button();
    b.Background = new SolidColorBrush(Colors.Black);
    b.Foreground = new SolidColorBrush(Colors.Black);
    //b.Width = 70;
    b.MinWidth = 70;
    b.Height = 25;
    b.Click += new RoutedEventHandler(b_Click);
    b.Content = p.ToString();
    bord.Child = b;
    TwitterListStack.Children.Add(bord);
}

Please note, I am setting the button width to be auto based on the content and also giving it a midwidth value. I wanted to create a rounded corner buttons, but for some reason its not working.

Also add this StackPanel – TwitterListStack of the Home.xaml

<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="TwitterListStack"></StackPanel>

After doing this, you would get a series of buttons in the top of the home page.

image

7) Now the button click event handler – b_Click, in this method, once the button is clicked, I call another method with the content string of the button which is clicked as the parameter.

Button b = (Button)e.OriginalSource;
getListStatuses(b.Content.ToString());

 

8) Now the getListsStatuses method:

toggleProgressBar(true);
WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
WebClient myService = new WebClient();
myService.AllowReadStreamBuffering = true;
myService.UseDefaultCredentials = false;
myService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimelineRequestCompleted);
if (listName.IndexOf("@") > -1 && listName.IndexOf("/") > -1)
{
    string[] arrays = null;
    arrays = listName.Split('/');
    arrays[0] = arrays[0].Replace("@", " ").Trim();
    //MessageBox.Show(arrays[0]);
    //MessageBox.Show(arrays[1]);
    string url = "http://api.twitter.com/1/" + arrays[0] + "/lists/" + arrays[1] + "/statuses.xml";
    //MessageBox.Show(url);
    myService.DownloadStringAsync(new Uri(url));
}
else
    myService.DownloadStringAsync(new Uri("http://api.twitter.com/1/" + GlobalVariable.getUserName() + "/lists/" + listName + "/statuses.xml"));

 

Please note that the url to look at will be different based on the list clicked – if its user created, the url format will be

http://api.twitter.com/1/<CurentUser>/lists/<ListName>/statuses.xml

But if it is some lists subscribed, it will be

http://api.twitter.com/1/<ListOwnerUserName>/lists/<ListName>/statuses.xml

The first one is pretty straight forward to implement, but if its a list subscribed, we need to split the listName string to get the list owner and list name and user them to form the string. So that is what I’ve done in this method, if the listName has got “@” and “/” I build the url differently.

9) Until now, we’ve been using only a few nodes of the status message xml string, now we will look to fetch a new field - “profile_image_url”. Images in datagrid – COOL. So for that, we need to modify our Status.cs file to include two more fields one string another BitmapImage with get and set.

public string profile_image_url { get; set; }
public BitmapImage profileImage { get; set; }

10) Now let us change the generic parseXML method which is used for binding to the datagrid.

public void parseXML(string text)
{
    XDocument xdoc;
    xdoc = XDocument.Parse(text);
    statusList = new List<Status>();
    statusList = (from status in xdoc.Descendants("status")
                  select new Status
                  {
                      ID = status.Element("id").Value,
                      Text = status.Element("text").Value,
                      Source = status.Element("source").Value,
                      UserID = status.Element("user").Element("id").Value,
                      UserName = status.Element("user").Element("screen_name").Value,
                      profile_image_url = status.Element("user").Element("profile_image_url").Value,
                      profileImage = new BitmapImage(new Uri(status.Element("user").Element("profile_image_url").Value))
                  }).ToList();
    DataGridStatus.ItemsSource = statusList;
    StatusMessage.Text = "Datagrid refreshed.";
    toggleProgressBar(false);
}

We are here creating a new bitmap image from the image url and creating a new Status object for every status and binding them to the data grid. Refer to the Twitter API documentation here. You can choose any column you want.

11) Until now, we’ve been using the auto generate columns for the data grid, but if you want it to be really cool, you need to define the columns with templates, etc…

<data:DataGrid AutoGenerateColumns="False" Name="DataGridStatus" Height="Auto" MinWidth="400">
<data:DataGrid.Columns>
    <data:DataGridTemplateColumn Width="50" Header="">
        <data:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <Image Source="{Binding profileImage}" Width="50" Height="50" Margin="1"/>
            </DataTemplate>
        </data:DataGridTemplateColumn.CellTemplate>
    </data:DataGridTemplateColumn>
    <data:DataGridTextColumn Width="Auto" Header="User Name" Binding="{Binding UserName}" />
    <data:DataGridTemplateColumn MinWidth="300" Width="Auto" Header="Status">
        <data:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock TextWrapping="Wrap" Text="{Binding Text}"/>
            </DataTemplate>
        </data:DataGridTemplateColumn.CellTemplate>
    </data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>

 

I’ve used only three columns – Profile image, Username, Status text. Now our Datagrid will look super cool like this.

image

Coincidentally,  Tim Heuer is on the screenshot , who is a Silverlight Guru and works on SL team in Microsoft. His blog is really super.

Here is the zipped file for all the xaml, xaml.cs & class files pages.

Ok let us stop here for now, will look into implementing few more features in the next few posts and then I am going to look into developing a ASP.NET MVC 2 application.

Hope you all liked this post. If you have any queries / suggestions feel free to comment below or contact me.

Cheers!

 

 


In this post, we will look at implementing the following in our twitter client - displaying the profile picture in the home page after logging in. So to accomplish this, we will need to do the following steps.

1) First of all, let us create another field in our Global variable static class to hold the profile image url. So just create a static string field in that.

public static string profileImage { get; set; }

 

2) In the Login.xaml.cs file, before the line where we redirect to the Home page if the login was successful. Create another WebClient request to fetch details from this url - .xml">http://api.twitter.com/1/users/show/<TwitterUsername>.xml I am interested only in the “profile_image_url” node in this xml string returned. You can choose what ever field you need – the reference to the Twitter API Documentation is here.

3) This particular url does not require any authentication so no need of network credentials for this and also the useDefaultCredentials will be true. So this code would look like.

WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
WebClient myService = new WebClient();
myService.AllowReadStreamBuffering = myService.UseDefaultCredentials = true;
myService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimelineRequestCompleted_User);)
myService.DownloadStringAsync(new Uri("http://api.twitter.com/1/users/show/" + TwitterUsername.Text + ".xml"));

4) To parse the xml file returned by this and get the value of the “profile_image_url” node, the LINQ code will look something like

XDocument xdoc;
xdoc = XDocument.Parse(e.Result);
var answer = (from status in xdoc.Descendants("user")
              select status.Element("profile_image_url").Value);
GlobalVariable.profileImage = answer.First().ToString();

5) After this, we can then redirect to Home page completing our login formalities.

6) In the home page, add a image tag and give it a name, something like

<Image Name="image1" Stretch="Fill" Margin="29,29,0,0" Height="73" VerticalAlignment="Top" HorizontalAlignment="Left" Width="73" />

 

7) In the OnNavigated to event in home page, we can set the image source url as below

image1.Source = new BitmapImage(new Uri(GlobalVariable.profileImage, UriKind.Absolute));

 

image

Hope this helps. If you have any queries / suggestions, please feel free to comment below or contact me.


Wednesday, March 24, 2010 #

Here you can download the source files this includes all the parts we have discussed and one more list feature which I am currently working on, its not fully finished. This is a VS2010 RC / SL 4 RC compliant version files, so make sure you use it with them. Will see you soon in my next post with the next part ready.

I received a few emails, saying that my tutorial is good – Thanks for all your support. A few asked for source files, here it is. All your support gives me more reasons to keep blogging!

Cheers! Smile


Tuesday, March 16, 2010 #

Finally Silverlight 4 RC is released and also that Windows 7 Phone Series will rely heavily on Silverlight platform for apps platform. its a really good news for Silverlight developers and designers. More information on this here. You can use SL 4 RC with VS 2010. SL 4 RC does not come with VS 2010, you need to download it separately and install it. So for the next part, be ready with VS 2010 and SL4 RC, we will start using them and not betas.

With this momentum, let us go to the next part of our twitter client tutorial. This tutorial will cover setting your status in Twitter and also retrieving your

1) As everything in Silverlight is asynchronous, we need to have some visual representation showing that something is going on in the background. So what I did was to create a progress bar with indeterminate animation. The XAML is here below.

<ProgressBar Maximum="100" Width="300" Height="50" Margin="20" Visibility="Collapsed" IsIndeterminate="True" Name="progressBar1" VerticalAlignment="Center" HorizontalAlignment="Center" />

2) I will be toggling this progress bar to show the background work. So I thought of writing this small method, which I use to toggle the visibility of this progress bar. Just pass a bool to this method and this will toggle it based on its current visibility status.

public void toggleProgressBar(bool Option)
{
    if (Option)
    {
        if (progressBar1.Visibility == System.Windows.Visibility.Collapsed)
            progressBar1.Visibility = System.Windows.Visibility.Visible;
    }
    else
    {
        if (progressBar1.Visibility == System.Windows.Visibility.Visible)
            progressBar1.Visibility = System.Windows.Visibility.Collapsed;
    }
}

3) Now let us create a grid to hold a textbox and a update button. The XAML will look like something below

<Grid HorizontalAlignment="Center">
    <Grid.RowDefinitions>
        <RowDefinition Height="50"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="400"></ColumnDefinition>
        <ColumnDefinition Width="200"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <TextBox Name="TwitterStatus" Width="380" Height="50"></TextBox>
    <Button Name="UpdateStatus" Content="Update" Grid.Row="1" Grid.Column="2" Width="200" Height="50" Click="UpdateStatus_Click"></Button>
</Grid>

4) The click handler for this update button will be again using the Web Client to post values. Posting values using Web Client. The code is:

private void UpdateStatus_Click(object sender, RoutedEventArgs e)
{
    toggleProgressBar(true);
    string statusupdate = "status=" + TwitterStatus.Text;
    WebRequest.RegisterPrefix("https://", System.Net.Browser.WebRequestCreator.ClientHttp);
 
    WebClient myService = new WebClient();
    myService.AllowReadStreamBuffering = true;
    myService.UseDefaultCredentials = false;
    myService.Credentials = new NetworkCredential(GlobalVariable.getUserName(), GlobalVariable.getPassword());
 
    myService.UploadStringCompleted += new UploadStringCompletedEventHandler(myService_UploadStringCompleted);
    myService.UploadStringAsync(new Uri("https://twitter.com/statuses/update.xml"), statusupdate);
 
    this.Dispatcher.BeginInvoke(() => ClearTextBoxValue());
}

5) In the above code, we have a event handler which will be fired on this request is completed – !! Remember SL is Asynch !! So in the myService_UploadStringCompleted, we will just toggle the progress bar and change some status text to say that its done. The code for this will be StatusMessage is just another textblock conveniently positioned in the page.

 
void myService_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
    if (e.Error != null)
    {
        StatusMessage.Text = "Status Update Failed: " + e.Error.Message.ToString();
    }
    else
    {
        toggleProgressBar(false);
        TwitterCredentialsSubmit();
    }
}

6) Now let us look at fetching the friends updates of the logged in user and displaying it in a datagrid. So just define a data grid and set its autogenerate columns as true.

7) Let us first create a data structure for use with fetching the friends timeline. The code is something like below:

namespace MaxTwitter.Classes
{
    public class Status
    {
        public Status() {}
        public string ID { get; set; }
        public string Text { get; set; }
        public string Source { get; set; }
        public string UserID { get; set; }
        public string UserName { get; set; }
    }
}

You can add as many fields as you want, for the list of fields, have a look at here. It will ask for your Twitter username and password, just provide them and this will display the xml file. Go through them pick and choose your desired fields and include in your Data Structure.

8) Now the web client request for this is similar to the one we saw in step 4. Just change the uri in the last but one step to

https://twitter.com/statuses/friends_timeline.xml

Be sure to change the event handler to something else and within that we will use XLINQ to fetch the required details for us. Now let us how this event handler fetches details.

public void parseXML(string text)
{
    XDocument xdoc;
    if(text.Length> 0)
        xdoc = XDocument.Parse(text);
    else
        xdoc = XDocument.Parse(@"I  USED MY OWN LOCAL COPY OF XML FILE HERE FOR OFFLINE TESTING");
    statusList = new List<Status>();
    statusList = (from status in xdoc.Descendants("status")
                  select new Status
                  {
                      ID = status.Element("id").Value,
                      Text = status.Element("text").Value,
                      Source = status.Element("source").Value,
                      UserID = status.Element("user").Element("id").Value,
                      UserName = status.Element("user").Element("screen_name").Value,
                  }).ToList();
    //MessageBox.Show(text);
    //this.Dispatcher.BeginInvoke(() => CallDatabindMethod(StatusCollection));
    //MessageBox.Show(statusList.Count.ToString());
    DataGridStatus.ItemsSource = statusList;
    StatusMessage.Text = "Datagrid refreshed.";
    toggleProgressBar(false);
}

in the event handler, we call this method with e.Result.ToString() Parsing XML files using LINQ is super cool, I love it.

 

image

I am stopping it here for  this post. Will post the completed files in next post, as I’ve worked on a few more features in this page and don’t want to confuse you. See you soon in my next post where will play with Twitter lists. Have a nice day!


Saturday, March 06, 2010 #

We will create a few classes now to help us with storing and retrieving user credentials, so that we don't ask for it every time we want to speak with Twitter for getting some information.

  1. Now the class to sorting out the credentials. We will have this class as a static so as to ensure one instance of the same. This class is mainly going to include a getter setter for username and password, a method to check if the user if logged in and another one to log out the user. You can get the code here.
  2. Now let us create another class to facilitate easy retrieval from twitter xml format results for any queries we make. This basically involves just creating a getter setter for all the values that you would like to retrieve from the xml document returned. You can get the format of the xml document from here. Here is what I've in my Status.cs data structure class.

    using System;

    using System.Net;

    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;

     

    namespace MaxTwitter.Classes

    {

    public class Status

    {

    public Status() {}

    public string ID { get; set; }

    public string Text { get; set; }

    public string Source { get; set; }

    public string UserID { get; set; }

    public string UserName { get; set; }

    }

    }

     

  3. Now let us looking into implementing the Login.xaml.cs, first thing here is if the user is already logged in, we need to redirect the user to the homepage, this we can accomplish using the event OnNavigatedTo, which is fired when the user navigates to this particular Login page. Here you utilize the navigate to method of NavigationService to goto a different page if the user is already logged in.

if (GlobalVariable.isLoggedin())

        this.NavigationService.Navigate(new Uri("/Home", UriKind.Relative));

 

  1. On the submit button click event, add the new event handler, which would save the perform the WebClient request and download the results as xml string.

WebRequest.RegisterPrefix("https://", System.Net.Browser.WebRequestCreator.ClientHttp);

 

The following line allows us to create a web client to create a web request to a url and get back the string response. Something that came as a great news with SL 4 for many SL developers.

 

WebClient myService = new WebClient();

myService.AllowReadStreamBuffering = true;

myService.UseDefaultCredentials = false;

myService.Credentials = new NetworkCredential(TwitterUsername.Text, TwitterPassword.Password);

 

Here in the following line, we add an event that has to be fired once the xml string has been downloaded. Here you can do all your XLINQ stuff.

 

myService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimelineRequestCompleted);

 

myService.DownloadStringAsync(new Uri("https://twitter.com/statuses/friends_timeline.xml"));

 

  1. Now let us look at implementing the TimelineRequestCompleted event. Here we are not actually using the string response we get from twitter, I just use it to ensure the user is authenticated successfully and then save the credentials and redirect to home page.

public void TimelineRequestCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)

{

if (e.Error != null)

{

MessageBox.Show("This application must be installed first");

}

 

If there is no error, we can save the credentials to reuse it later.

 

else

{

GlobalVariable.saveCredentials(TwitterUsername.Text, TwitterPassword.Password);

this.NavigationService.Navigate(new System.Uri("/Home", UriKind.Relative));

}

}

  1. Ok so now login page is done. Now the main thing – running this application. This credentials stuff would only work, if the application is run out of the browser. So we need fiddle with a few Silverlioght project settings to enable this. Here is how:

     

     

    Right click on Silverlight > properties then check the "Enable running application out of browser".

     

     

    Then click on Out-Of-Browser settings and check "Require elevated trust…" option. That's it, all done to run. Now press F5 to run the application, fix the errors if any. Then once the application opens up in browser with the login page, right click and choose install.

     

    Once you install, it would automatically run and you can login and can see that you are redirected to the Home page. Here are the files that are related to this posts. We will look at implementing the Home page, etc… in the next post. Please post your comments and feedbacks; it would greatly help me in improving my posts!

     

    Thanks for your time, catch you soon.