Writing better code

A key factor to being a successful developer is writing good, solid, maintainable, error free code. It seems like a pretty obvious – albeit innocuous – statement, so why state the obvious? When you check code into the main branch of the source code for your organisation, you immediately expose your abilities and disabilities as a developer to the people you work with and for. If you check in a bad bit of code that contains bugs, it usually isn’t you that first notices the bug, but a colleague and you can look inept, especially if it is a silly mistake (and you have made a few of them – your boss may start thinking you are inapt to continue in your role in the company).

Writing good code is very difficult, especially when the code base is changing rapidly so you as a developer need tools that can make your life easier. The more experienced you become as a developer, the more you look to ways of making your life easier. Jetbrains have a visual studio add-in called ReSharper that is a little like FxCop, which the smarter developers amongst us use. If you are wondering why some developers seem to produce very clean code consistently that omits silly bugs (even on a Friday afternoon), you will more than likely find that they are using ReSharper.

I don’t doubt that a lot of people may dislike the fact that this takes over your IDE (this really is for the better though), in fact, If I recollect correctly I tried ReSharper a few times, then removed it (after a few word of mouth trials) every time because my IDE was less responsive, and because I was impetuous. It was only when I released a test application to a customer a few months ago (that kept crashing unexpectedly), when desperation set in, and drove me (frantically) looking for errors in my code. The main culprit  (in this specific instance) was a handful of null references in the codebase that had gone unnoticed, that ReSharper readily identified and I corrected, consequently achieving rapid application stability, over the course of a few days long code review. I’m not saying that all my problems were fixed, but most of the niggling issues were, with little to no effort.

It is not just null checks that ReSharper identifies, but a pretty comprehensive set of common coding mistakes that even the best programmers frequently make. The ‘Big Win’ is in that you get to correct problems there and then, as the code is written, before it becomes an issue. Visual Studio 2008 introduced background compilation that surreptitiously increases developer productivity by showing them errors as the code is typed, rather than waiting to press F5. ReSharper is orders of magnitude more helpful, if you use it correctly, you end up with a very clean codebase, with no unnecessary code, that has had common errors identified, giving you the developer confidence in your code.

To show a few basic examples

22-05-2010 15-16-47

Here I can remove the redundant delegate constructor call that the IDE generates. I can also remove the this keyword. The this keyword is rather abused in C# (Me in Visual Basic) and a lot of code samples (even from Microsoft) show developers misguided bliss with the word. One only ever needs to use the word when you have two variables named the same in a class (typically in a constructor) like this

22-05-2010 15-26-58

In most other cases it is redundant to use the word.

22-05-2010 15-21-35

In the sample above there are several issues. I have dead namespaces at the top, a poorly named control, two poorly named variables, that can also be made readonly. This is just an iota of the static runtime assistance that you get as a developer, and you can adopt the mantra of “writing a little code that does a lot”, rather than “writing a lot of code that does a lot”, with significantly less bugs.

I strongly encourage you to download this tool, acquaint yourself with it, and start working a little smarter (even on Friday afternoon).

Windows Phone 7 – The Real Game Changer

 

Excitation

I am really exited in the direction Microsoft has taken with Windows Presentation Foundation and Silverlight, in that they have really demonstrated that they see these two technologies as the future of their user interface based aspects in their software by making significant investment in the technology. For a start, they have used WPF to great effect in Visual Studio 2010. Frequently, I spend 10 to 12 hours in Visual Studio and it is an absolute joy to use the 2010 version as the previous user interface that had not changed for a decade was showing its age. The number of enhancements in Visual Studio is plethoric, and includes automatically generated UML diagrams all done in WPF, but that really is another subject in itself.

A brief history

I decided to move the focus of my development over a year ago to WPF after spending a number of years in Windows Forms, before that it had been Delphi, before that C/C++ and domain specific languages primarily used in the medical, banking and defence industries. It was a bit of a gamble, because if you live outside of London (I am in Manchester), then WPF jobs are few and far between, as most business that required investment in software to gain the competitive edge has already done so. The opportunities with WPF and Silverlight usually arise in start-ups, of which I am involved in one at present. The exciting thing is not being tied to a codebase that is many years old, with a license to use the latest and greatest software. I moved the project I was working on to .NET 4.0 the day it was released, without needing endless meetings deliberating about the why, that what and the what for. It is beginning to look as the gamble I took has paid off, as I have overnight become a Windows Phone 7 developer. This included being a Silverlight developer as well.

Windows Phone 7

I, like many people use my mobile phone daily, and cannot imagine what it would be like not to have a mobile phone. I have been a little sceptical about the real usefulness of iPhone applications, as most of them presented themselves as bubblegum to me. Taste sweet for five minutes, then endlessly insipid afterwards. I have also been put off by having to learn objective C and the Apple implementation. The only Apple product I have owned was a G4 some years ago, but it ended up unused as it was not suited to the kind of development I needed to do at the time. My current mobile phone contact is up in a months time, I had resigned myself to getting an iPhone, simply because it is one of the best phones on the market, with a breadth of applications, something my current phone lacks.

I watched the announcement at Mix for the Windows Phone 7 with glee, and with the leaked images of a Dell phone (courtesy of Engadget) I resolved that I would have to wait till Christmas using my current phone as I had become a Windows Phone developer overnight

04-21-10lightningg4

Tools

I would say the chief issue that determines whether I do something or not now is how long it will take me. My time is very limited, so anything that requires a steep learning curve without a significant return of investment for that time usually means that I won’t look twice at it. this is also true for Microsoft release CTP’s so frequently it can be hard to keep up. I decided to download the CTP for Windows Phone 7, as a release that integrates with Visual Studio 2010 RTM has now been made available here. The installation was quick and polished enough to give me the confidence that it should not break my Visual Studio  installation. What you get is a version of Visual Studio Express (seems to me only C# at the moment, so I hope a Visual Basic version is available or is in the pipeline) that included the following template (also installed into Visual Studio 2010)

30-04-2010 08-49-09

After choosing the Windows Phone Application you get what looks more like a WPF application rather than a Silverlight application

30-04-2010 08-55-36

Press F5 and you get an emulator for the phone that contains a working version of Internet Explorer and the eye catching transitions between pages

30-04-2010 09-01-51

looking at the nuts and bolts of the thing, they are using the Navigation pattern that is so familiar to me, it seems like I am writing a WPF application. I will dig deeper into how one can leverage their existing skills to create a simple application for Windows Phone 7

Syntax Highlighting In Blogs/Websites From Visual Studio for C#, F#, Visual Basic, XML, XAML etc.

When time permits, I enjoy writing the odd article for my blog, and tend to post code samples pretty frequently. There are a number of syntax highlighting tools available (even as add-ons for Windows Live Writer that I compose all my blog posts in) that you find interspersed in blogs over the internet.

I ran into an issue where I was upgrading from Windows Vista to Windows 7 where the live writer add-in stopped working, and transmogrified my code in blog posts, and there was no way to retrieve code if it was a previous post in Windows 7 (used my Vista laptop). I resolved then to seek an alternative solution that emitted pure HTML.

After some trawling about the interwebs, I found the excellent CopySourceAsHtml on Codeplex. When you select code in Visual Studio and highlight it, there is an additional context menu option available to “copy the source as HTML”

copysourceashtml

Selecting this brings up the following form where you can format your code

options

Clicking on OK allows me to paste my code as HTML in C#, Visual Basic and F# thus;

C#

   17     /// <summary>

   18     /// Interaction logic for Window1.xaml

   19     /// </summary>

   20     public partial class Window1 : Window

   21     {

   22         public Window1()

   23         {

   24             InitializeComponent();

   25         }

   26     }

 

  Visual Basic 

    1 Class Window1

    2     Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

    3         MessageBox.Show("CopySourceAsHTML is cool")

    4     End Sub

    5 End Class

F#

   57 /// Compute the highest-common-factor of two integers

   58 let rec hcf a b =                       // notice: 2 parameters separated by spaces

   59     if a=0 then b

   60     elif a<b then hcf a (b-a)           // notice: 2 arguments separated by spaces

   61     else hcf (a-b) b

   62     // note: function arguments are usually space separated

   63     // note: ‘let rec’ defines a recursive function

There is however, a limitation in the Visual Studio 2008 version where you do not get the context menu option when trying to copy XAML. You could do a copy and paste of the .xaml into an .xml file, as the option is available there, but that can get a bit cumbersome.

The easiest “workaround”, is to create a Visual Studio keyboard shortcut. In Visual Studio select Tools then Options, which should bring up the following dialogue;

copy

If you start typing copysour as per arrow above, you should be taken to the CopySourceAsHTML.Copy command. Whilst this is selected, move mouse focus into the Press shortcut keys textbox and press CTRL+Shift+C on your keyboard (or whatever keystrokes you desire), and then press the Assign button. You should have the following;

Assigned

you should then find that if you are in XAML you can CTRL+Shift+C and copy the .xaml thus;

    1 <Window x:Class="SyntaxHighlightingExampleCS.Window1"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

    4    Title="Window1" Height="300" Width="300">

    5     <Grid>

    6 

    7     </Grid>

    8 </Window>

Free WPF Themes

A little while back I noted that reuxables were gathering steam. Slightly earlier that year, we were all wowed by the Lawson Mango application

lawson_m3_cs_1

as this was a clear illustration that WPF could offer a vector based visual experience that left your ‘jaw on the floor’. Reuxables have now released a free version of the above theme called Inc

inc

I have been using this in my WPF applications, and have grown rather quite fond of it, principally because WPF themes can be a bit ‘too much’ for applications that one uses daily. You can get the theme here (there is also a free Metal theme [below] if that takes your fancy)

Metal

Improve the quality of your code with NDepend

Before a parachutist, mountain climber or formula one driver undertake their tasks, a number of checks need to be undertaken. These checks will assist in deciding whether the parachutist for instance will even jump out of the plane. If a typhoon is on the way, all are likely to wait until it has passed, the type of climbing gear the mountain climber will choose, must depend on the type of mountain they are to climb. What all these checks result in, is less surprises, in computer programming this is analogous to bugs.

The Ironbridge Shropshire

I know that architecture is ubiquitously used to describe engineering software, but the comparison is indeed an irresistible one. Take the Ironbridge in Shropshire for example, every element of this engineering feat must have been stress tested. The materials must have been tested to see how they react to temperature changes, weight and so forth. You can even find out how many rivets they used, and the length of the steel used in the bridge, all wonderful and useful information. Shropshire bridge (as I’m sure your well aware) is not the only bridge in the world, as there are a great many others that come in different shapes and sizes and age. The design process for a lot of these constructions requires a similar set of circumstances and considerations. A formula one motor car for example, still has four wheels as does a mini cooper. Writing software is no different, and most if not all software projects entail a similar set of circumstances and considerations, whether massive, big or small, you still want to deliver a fast, efficient, reliable and effective application.

I have recently started using NDepend, to quote from their website;

NDepend is a tool that simplifies managing a complex .NET code base. Architects and developers can analyze code structure, specify design rules, plan massive refactoring, do effective code reviews and master evolution by comparing different versions of the code

NDependMain

If you prefer the ribbon, you can change the user interface to suit

Ribbon

The way I look at my code has been changed forever. What you get is an abundance of relevant and pertinent information about your code, that you never thought possible. NDepend is about assisting you the developer (whether a single man outfit or team) to ensure that you are producing the highest quality code possible. There is so much information at your fingertips, it is overwhelming.

The Model View Controller, Model View Presenter and Model View View Model design patterns for example, are all about separating the concerns of your code, and increasing the testability of your code base. NDepend is another necessary tool, in that when you perform code reviews, it becomes an indispensable tool. Architects for a project can set rules for the code base, and easily check to see that they have been adhered to from a quality point-of-view, and developers themselves can ensure that they remove any sloppy code they’ve written, and spot anomalies and problem areas before they check in their code.

Here I have just loaded an assembly for an application that I wrote a while ago. I have a pane (one of many) that furnishes me with information about the number of lines of code I have for instance, comments, methods, fields and types.

ProjectLines

In another pane, you have information pertaining to code quality, methods that are too big, methods that are too complex, methods to refactor, methods with too many variables, methods with too many parameters, the list goes on and on. Each point an important code quality concern.

CodeQuality

In the same pane under design, you have suggestions that stateless types in the code could be changed to static types, or that a class without a descendant should be sealed, and again a myriad of other code quality issues that need to be addressed.

Design

Why should it be sealed? The sealed modifier is primarily used to prevent unintended derivation, but it also enables certain run-time optimizations. In particular, because a sealed class is known to never have any derived classes, it is possible to transform virtual function member invocations on sealed class instances into non-virtual invocations.  You have 5 classes here that can be changed to Structs, improving performance as they are now value types and not reference types from a .NET runtime standpoint.

You have Visual studio integration, Reflector integration and a wealth of other features.

VSIntegration

An issue any Software architect or Developer always runs into is performance and trying to ensure that their code is as optimised as possible, ensuring that their end users have the best possible experience when they use an application. I have always used this article every once in a while to ensure that my applications are structured correctly, and refer to it every now and again (most of the article is relevant to Silverlight and WPF as well). Clearly by using NDepend you will end up with better performing applications, and also more maintainable codebases, because all the ‘gremlins’ are ‘found out’ soon and the more you review your code with it, the better quality your code will be as a result.

NDepend is an essential new development tool, that I will blog about more, once I understand it better.

WPF and Silverlight Timer

Users of Windows Forms will know that there are three timer objects you can use, namely the Windows Forms Timer, the System Timers Timer and finally the System Threading Timer, as the following example demonstrates;

Note: this tutorial is in both C# and Visual Basic, so look beneath the Visual Basic examples for the C# Version.

Visual Basic

Public Class Form1

 

    Dim timerCallBack As System.Threading.TimerCallback

 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ”Winforms Timer

        Dim wfTimer As System.Windows.Forms.Timer()

 

        ”Timers Timer

        Dim tTimer As System.Timers.Timer()

 

        ”Threading Timer

        timerCallBack = AddressOf PrintTime

        Dim thTimer As System.Threading.Timer = New System.Threading.Timer(Me.timerCallBack)

 

 

    End Sub

 

    Private Sub PrintTime(ByVal obj As System.Object)

        ”Print the time to screen

    End Sub

 

 

End Class

C#

using System.Windows.Forms;

 

namespace TimersExample

{

    public partial class Form1 : Form

    {

        System.Threading.TimerCallback timerCallBack;

 

        public Form1()

        {           

            InitializeComponent();

        }

        private void Form1_Load(object sender, System.EventArgs e)

        {

            // Winforms Timer

            System.Windows.Forms.Timer wfTimer = new Timer();

 

            //Timers Timer

            System.Timers.Timer tTimer = new System.Timers.Timer();

 

            //Threading Timer

            timerCallBack = new System.Threading.TimerCallback(PrintTime);

            System.Threading.Timer thTimer = new System.Threading.Timer(this.timerCallBack);

        }

        private void PrintTime(object obj)

        {

            //Print the time to screen

        }

 

    }

}

 

In both WPF and Silverlight there is a new timer (the fourth .NET framework timer) called the System.Windows.Threading.DispatcherTimer. To demonstrate how this works, look at the following simple code sample. In it, there is some XAML that declares a label, button and a button click and window loaded events (In Silverlight use the UserControl_Loaded event for the page instead of Window_Loaded).

 

<Window x:Class="WpfTimer.Window1"

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

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

   Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">

    <Grid>

 

        <StackPanel Orientation="Vertical">

        <Label Height="28" Width="70" Name="label1">Label</Label>

        <Button Height="23" Width="70" Name="button1" Click="button_Click">Button</Button>

 

        </StackPanel>

 

    </Grid>

</Window>

 

Note that in the Visual Basic XAML you have Window x:Class="Window1" at the top (in case you’re wondering why the XAML does not compile). In the code behind, you have the following code that instantiates a DispatcherTimer in the load event of the Window, and allows a user from starting and stopping the timer by toggling the button click event.

   

Visual Basic

Class Window1

    Dim timer As System.Windows.Threading.DispatcherTimer

    Public Event UpdateTime()

 

    Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)

        timer = New System.Windows.Threading.DispatcherTimer()

        timer.Interval = TimeSpan.FromSeconds(1)

        AddHandler timer.Tick, AddressOf timer_Tick

 

    End Sub

 

    Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs)

        Me.label1.Content = DateTime.Now.ToLongTimeString()

    End Sub

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)

        If Not Me.timer.IsEnabled Then

            Me.timer.Start()

            Me.button1.Content = "Stop"

        Else

            Me.timer.[Stop]()

            Me.button1.Content = "Start"

        End If

    End Sub

 

 

 

 

End Class

 

C#

using System;

using System.Windows;

 

namespace WpfTimer

{

    /// <summary>

    /// Interaction logic for Window1.xaml

    /// </summary>

    public partial class Window1 : Window

    {

        System.Windows.Threading.DispatcherTimer timer;

 

        public Window1()

        {

            InitializeComponent();         

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            timer = new System.Windows.Threading.DispatcherTimer();

            timer.Interval = TimeSpan.FromSeconds(1);

            timer.Tick += new EventHandler(timer_Tick);

        }

 

        void timer_Tick(object sender, EventArgs e)

        {

            this.label1.Content = DateTime.Now.ToLongTimeString();

        }

 

        private void button_Click(object sender, RoutedEventArgs e)

        {

            if (!this.timer.IsEnabled)

            {

                this.timer.Start();

                this.button1.Content = "Stop";

            }

            else

            {

                this.timer.Stop();

                this.button1.Content = "Start";

            }

        }

 

 

    }

}

 

DispatcherTimer

Free Training worth £5000

It’s not often that you find something that is too good to be true, but this is. Microsoft are offering free Windows Presentation Foundation training by two of their leading proponents on the technology Jaime Rodriguez and Karl Shiftlett.

The agenda for training will be

Day One:

  • Lap Around WPF
  • WPF Tools ( Blend, Visual Studio 2008)
  • Graphics Subsystem
  • Layout
  • WPF Fundamentals and new concepts
    • Application Model
    • Dependency Properties
    • Trees (logical & visual)
    • Events
    • Threading
    • Resources
  • Controls
  • Styling
  • Templating
  • Q&A with instructors at end of day
  • Day Two:
    • WPF integration with Win32 and Windows Forms
    • Data binding
    • Introduction to Model-View-ViewModel
    • Commanding in M-V-VM
    • Views, Navigation and Transitions
    • Data Validation
    • Error handling, Model dialogs, Logging
    • Unit Testing
    • MVVM & LOB tips and tricks
    • Q&A with the instructors

I have signed up for this training, and think that it is a seriously good offer, that you won’t find anywhere, especially seeing as the training will be coming from the “horses mouth” so to speak!

Windows API Code Pack for the .NET Library

In this post I demoed some of the managed wrappers that are available for .NET developers to target the Windows Vista and Windows 7 API’s. The Vista Bridge has now been officially renamed to Windows API Code Pack for the .NET Library and will be available after Window 7 is released.

I must express some disappointment, that this is going to be made available as a separate library, as I would have much preferred it if this was a part of the forthcoming .NET framework 4.0., and I could use the controls in Visual Studio. It may wall be that Windows 7 will be released before .NET Framework 4.0., which may well explain this, as anyone that has tried the Windows 7 beta, will attest to it containing .NET Framework 3.5 SP1 only.

Building a Composite WPF and Silverlight Application with Prism – Part 4

Welcome to the final part in this four part series on building a WPF and Silverlight application with Prism. The previous parts are

Building a Composite WPF and Silverlight Application with Prism – Part 1

Building a Composite WPF and Silverlight Application with Prism – Part 2

Building a Composite WPF and Silverlight Application with Prism – Part 3

The main focus of this tutorial will be introducing communication between modules. Thus far, we have focussed on getting the Digg module operational. In this instalment we will add a search module, and demonstrate how this separate module can interact with another in a loosely coupled fashion.

This tutorial is in both C# and Visual Basic, but when creating projects in Visual Studio, the images I may use may be C# templates for example, but you should be able to do exactly the same in Visual Basic and vica-versa. It avoids the repetition of posting two images with “Open C# Silverlight Application” and “Open Visual Basic Application”, when the Visual Studio templates are the same – bar the language. I will however, post code samples in both languages

Adding the Search Module

Add a new Silverlight class library to the solution, and call this NewsAggregator.Search and delete the default class1 added to the project

SearchModule

Add references to the Prism libraries (in C# right click the References node in Solution Explorer and choose “Add Reference…” )

AddReferences

add a SearchModule class to this project that implements IModule and implement the interface.

Visual Basic

Imports Microsoft.Practices.Composite.Modularity

 

Public Class SearchModule

    Implements IModule

 

 

    Public Sub Initialize() Implements Microsoft.Practices.Composite.Modularity.IModule.Initialize

 

    End Sub

End Class

C#

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;

using Microsoft.Practices.Composite.Modularity;

 

namespace NewsAggregator.Search

{

    public class SearchModule : IModule

    {

 

        #region IModule Members

 

        public void Initialize()

        {

            //throw new NotImplementedException();

        }

 

        #endregion

    }

}

 

Add a reference of the NewsAggregator.Search library to the NewsAggregator.Shell and add the SearchModule to the Bootstrapper. Note that this as in the previous example is setting a direct reference to the Shell. This is to hasten the tutorials, but typically you want to add this or any other module in a loosely coupled fashion was well.

 

Visual Basic

Imports Microsoft.Practices.Composite.UnityExtensions

Imports Microsoft.Practices.Composite.Modularity

Imports NewsAggregator.Digg

Imports NewsAggregator.Search

 

 

Public Class Bootstrapper

    Inherits UnityBootstrapper

 

    Protected Overrides Function CreateShell() As System.Windows.DependencyObject

        Dim shell As New Shell

        Application.Current.RootVisual = shell

        Return shell

    End Function

    Protected Overrides Function GetModuleCatalog() As Microsoft.Practices.Composite.Modularity.IModuleCatalog

        Dim catalog As New ModuleCatalog

        catalog.AddModule(GetType(DiggModule))

        catalog.AddModule(GetType(SearchModule))

        Return catalog

    End Function

 

End Class

 

C#

using System.Windows;

using Microsoft.Practices.Composite.UnityExtensions;

using Microsoft.Practices.Composite.Modularity;

using NewsAggregator.Digg;

using NewsAggregator.Search;

 

namespace NewsAggregator.Shell

{

    public class Bootstrapper : UnityBootstrapper

    {

 

        protected override DependencyObject CreateShell()

        {

            Shell shell = new Shell();

            Application.Current.RootVisual = shell;

            return shell;

        }

        protected override Microsoft.Practices.Composite.Modularity.IModuleCatalog GetModuleCatalog()

        {    

            ModuleCatalog catalog = new ModuleCatalog();

            catalog.AddModule(typeof(DiggModule));

            catalog.AddModule(typeof(SearchModule));

            return catalog;

        }

    }

}

 

Implementing the Search Model View View Model

Adding the Model View

Add a UserControl to the NewsAggregator.Search library and call this SearchView

SearchView

In this UserControl add the following XAML

<UserControl x:Class="NewsAggregator.Search.SearchView"

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

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

    <UserControl.Resources>

        <Style x:Key="TitleBorder" TargetType="Border">

            <Setter Property="CornerRadius" Value="10"/>

            <Setter Property="Background" Value="#FFDEDEDE"/>

            <Setter Property="Margin" Value="0,0,5,0"/>

            <Setter Property="Grid.Column" Value="0"/>

        </Style>

 

        <Style x:Key="TitleText" TargetType="TextBlock">

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="Foreground" Value="#FF14517B"/>

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

        </Style>

 

        <Style x:Key="SearchButton" TargetType="Button">

            <Setter Property="Grid.Column" Value="2"/>

        </Style>

 

 

    </UserControl.Resources>

    <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"/>

            <ColumnDefinition Width="200"/>

            <ColumnDefinition Width="100"/>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition/>

        </Grid.RowDefinitions>

        <Border Style="{StaticResource TitleBorder}">

            <TextBlock Text="NEWS SEARCH " Style="{StaticResource TitleText}" />

        </Border>

 

        <TextBox x:Name="txtSearchTopic" Grid.Column="1" Padding="1,3,1,1" />     

 

        <Button Content="Search" Style="{StaticResource SearchButton}" />

 

 

    </Grid>

</UserControl>

which should result in the following user interface

SearchUI

Adding the View Model

When you click on search, normally you would be handle this by creating an event handler for the search button, but this is not easily testable. Implementing the MVVM pattern here will help with testing.

Add a new class library and call this SearchViewModel. In this library expose an ICommand with a private “setter” so this can be set in the constructor.

Note : Silverlight does not provide an commanding infrastructure here (but WPF does) so Prism has some commanding implementations that can be used. The easiest one to use is the Delegate command because we want to fire off a message on this ViewModel. In the constructor create a new SearchCommand that is a delegate command.Be cognisant that you have to pass in the type it will take (a search string in this case) and then point it to the method (the button click)

Now that the delegate command has been written, bind this method to the button, by adding binding in the XAML (again note that the commanding available in WPF is missing, but the Practices library has an implementation so include the namespace declaration at the top)

   xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"

Now add the binding to the search button

        <TextBox x:Name="txtSearchTopic" Grid.Column="1" Padding="1,3,1,1" />     

 

        <Button Content="Search" Style="{StaticResource SearchButton}" Commands:Click.Command="{Binding SearchCommand}" />

The SearchCommand binding is the one in the ViewModel that takes a search string as a parameter. In the XAML above you need to somehow pass whatever is entered in the TextBox into the command that is fired when the button is search button clicked. this is easily achieved in WPF but in Silverlight you can only bind to either the DataContext or static resources. To get this to work add a property called Title in the SearchViewModel, add and implement INotifyPropertyChanged as follows

Visual Basic

Imports Microsoft.Practices.Composite.Presentation.Commands

Imports System.ComponentModel

 

Public Class SearchViewModel

    Implements INotifyPropertyChanged

 

    Private _SearchCommand As ICommand

    Public Property SearchCommand() As ICommand

        Get

            Return _SearchCommand

        End Get

        Private Set(ByVal value As ICommand)

            _SearchCommand = value

        End Set

    End Property

 

    Public Sub New()

        Me.SearchCommand = New DelegateCommand(Of String)(AddressOf OnSearch)

    End Sub

 

    Private Sub OnSearch(ByVal title As String)

    End Sub

 

    Private _Title As String

 

    Public Property Title() As String

        Get

            Return Me._Title

        End Get

        Set(ByVal value As String)

            Me._Title = value

            OnPropertyChanged("Title")

        End Set

    End Property

 

#Region "INotifyPropertyChanged Members"

 

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

 

#End Region

 

#Region "INotifyPropertyChanged Members"

 

    Protected Sub OnPropertyChanged(ByVal propertyName As String)

        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))

    End Sub

 

#End Region

 

 

 

End Class

C#

using System.Windows.Input;

using Microsoft.Practices.Composite.Presentation.Commands;

using System.ComponentModel;

 

namespace NewsAggregator.Search

{

    public class SearchViewModel : INotifyPropertyChanged

    {

        public ICommand SearchCommand { get; private set; }

 

        public SearchViewModel()

        {

            this.SearchCommand = new DelegateCommand<string>(OnSearch);

        }

 

        private void OnSearch(string title)

        {

        }

 

        private string title;

 

        public string Title

        {

            get

            {

                return this.title;

            }

            set

            {

                this.title = value;

                OnPropertyChanged("Title");

            }

        }

 

        #region INotifyPropertyChanged Members

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        #endregion

 

        #region INotifyPropertyChanged Members

 

        protected void OnPropertyChanged(string propertyName)

        {

            if (this.PropertyChanged != null)

            {

                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

 

        #endregion

    }

}

So a property has now been created that you can bind against. Add the following binding to the textbox, and ensure two way binding is used so all the changes are synchronised back into the model, and add the command parameter to the search button. the XAML in the SearchView should look like this

<UserControl x:Class="NewsAggregator.Search.SearchView"

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

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

   xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation">

    <UserControl.Resources>

        <Style x:Key="TitleBorder" TargetType="Border">

            <Setter Property="CornerRadius" Value="10"/>

            <Setter Property="Background" Value="#FFDEDEDE"/>

            <Setter Property="Margin" Value="0,0,5,0"/>

            <Setter Property="Grid.Column" Value="0"/>

        </Style>

 

        <Style x:Key="TitleText" TargetType="TextBlock">

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="Foreground" Value="#FF14517B"/>

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

        </Style>

 

        <Style x:Key="SearchButton" TargetType="Button">

            <Setter Property="Grid.Column" Value="2"/>

        </Style>

 

 

    </UserControl.Resources>

    <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"/>

            <ColumnDefinition Width="200"/>

            <ColumnDefinition Width="100"/>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition/>

        </Grid.RowDefinitions>

        <Border Style="{StaticResource TitleBorder}">

            <TextBlock Text="NEWS SEARCH " Style="{StaticResource TitleText}" />

        </Border>

 

        <TextBox x:Name="txtSearchTopic" Grid.Column="1" Padding="1,3,1,1"

                Text="{Binding Path=Title, Mode=TwoWay}"/>

 

        <Button Content="Search" Style="{StaticResource SearchButton}"

               Commands:Click.Command="{Binding SearchCommand}"

               Commands:Click.CommandParameter="{Binding Path=Title}"/>

 

 

    </Grid>

</UserControl>

So what happens now is that when text is entered in the textbox it is synchronised back to the SearchViewModel and it is also bound to the search button.

Set the data context of the SearchView to the SearchViewModel

Visual Basic

Partial Public Class SearchView

    Inherits UserControl

 

    Public Sub New(ByVal viewModel As SearchViewModel)

        InitializeComponent()

        Me.DataContext = viewModel

    End Sub

 

End Class

C#

using System.Windows.Controls;

 

namespace NewsAggregator.Search

{

    public partial class SearchView : UserControl

    {

        public SearchView(SearchViewModel viewModel)

        {

            InitializeComponent();

            this.DataContext = viewModel;

        }

    }

}

Now ensure that this View shows up in the Region that has been created, by going to the SearchModule and using constructor injection again.

Visual Basic

Imports Microsoft.Practices.Composite.Modularity

Imports Microsoft.Practices.Composite.Regions

 

Public Class SearchModule

    Implements IModule

 

    Private _RegionManager As IRegionManager

    Public Sub New(ByVal regionManager As IRegionManager)

        Me._RegionManager = regionManager

    End Sub

    Public Sub Initialize() Implements Microsoft.Practices.Composite.Modularity.IModule.Initialize

        Me._RegionManager.RegisterViewWithRegion("SearchRegion", GetType(SearchView))

    End Sub

 

 

End Class

C#

using Microsoft.Practices.Composite.Modularity;

using Microsoft.Practices.Composite.Regions;

 

namespace NewsAggregator.Search

{

    public class SearchModule : IModule

    {

        private IRegionManager regionManager;

        public SearchModule(IRegionManager regionManager)

        {

            this.regionManager = regionManager;

        }

 

        #region IModule Members

 

        public void Initialize()

        {

            this.regionManager.RegisterViewWithRegion("SearchRegion", typeof(SearchView));

        }

 

        #endregion

    }

}

If you run the application you should find that the search module has been added

SearchModule

Decoupled Communication Mechanism

You will notice that the hard wired baseball query it still being used. To set up this decoupled communication two things are going to be required. In Prism there are quite a few ways that this can be achieved, but the EventAggregator will be used in this demo. This gives you access to a publish and subscribe mechanism where you can have multiple publishers for a topic and multiple subscribers as well.

Add a new Silverlight project (this is usually referred to as an infrastructure module) called NewsAggregator.Infrastructure and delete the default class1 that is added

Infrastructure

add references to the Patterns & Practices libraries

Libraries

add a class called SearchEvent that inherits from CompositePresentationEvent

Visual Basic

Imports Microsoft.Practices.Composite.Presentation.Events

 

Public Class SearchEvent

    Inherits CompositePresentationEvent(Of String)

 

 

End Class

C#

using Microsoft.Practices.Composite.Presentation.Events;

 

namespace NewsAggregator.Infrastructure

{

    public class SearchEvent : CompositePresentationEvent<string>

    {

 

    }

}

 

In the NewsAggregator.Search project, add a reference to the NewsAggregator.Infrastructure project

 

AddInfrastucture

 

in the constructor of the SearchViewModel add an event aggregator event to the constructor, and publish the “Title” in the OnSearch method

 

Visual Basic

Imports Microsoft.Practices.Composite.Presentation.Commands

Imports System.ComponentModel

Imports Microsoft.Practices.Composite.Events

Imports NewsAggregator.Infrastructure

 

Public Class SearchViewModel

    Implements INotifyPropertyChanged

 

    Private _SearchCommand As ICommand

    Public Property SearchCommand() As ICommand

        Get

            Return _SearchCommand

        End Get

        Private Set(ByVal value As ICommand)

            _SearchCommand = value

        End Set

    End Property

    Private _eventAggregator As IEventAggregator

 

    Public Sub New(ByVal eventAggregator As IEventAggregator)

        Me.SearchCommand = New DelegateCommand(Of String)(AddressOf OnSearch)

        Me._eventAggregator = eventAggregator

    End Sub

 

 

 

    Private Sub OnSearch(ByVal title As String)

        Me._eventAggregator.GetEvent(Of SearchEvent).Publish(title)

    End Sub

 

    Private _Title As String

 

    Public Property Title() As String

        Get

            Return Me._Title

        End Get

        Set(ByVal value As String)

            Me._Title = value

            OnPropertyChanged("Title")

        End Set

    End Property

 

#Region "INotifyPropertyChanged Members"

 

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

 

#End Region

 

#Region "INotifyPropertyChanged Members"

 

    Protected Sub OnPropertyChanged(ByVal propertyName As String)

        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))

    End Sub

 

#End Region

End Class

 

C#

using System.Windows.Input;

using Microsoft.Practices.Composite.Presentation.Commands;

using System.ComponentModel;

using Microsoft.Practices.Composite.Events;

using NewsAggregator.Infrastructure;

namespace NewsAggregator.Search

{

    public class SearchViewModel : INotifyPropertyChanged

    {

        public ICommand SearchCommand { get; private set; }

 

        private IEventAggregator eventAggregator;

        public SearchViewModel(IEventAggregator eventAggregator)

        {

            this.SearchCommand = new DelegateCommand<string>(OnSearch);

            this.eventAggregator = eventAggregator;

        }

 

        private void OnSearch(string title)

        {

            this.eventAggregator.GetEvent<SearchEvent>().Publish(Title);

        }

 

        private string title;

 

        public string Title

        {

            get

            {

                return this.title;

            }

            set

            {

                this.title = value;

                OnPropertyChanged("Title");

            }

        }

 

        #region INotifyPropertyChanged Members

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        #endregion

 

        #region INotifyPropertyChanged Members

 

        protected void OnPropertyChanged(string propertyName)

        {

            if (this.PropertyChanged != null)

            {

                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

 

        #endregion

    }

}

 

This is the first half of setting the event aggregation, now we need to configure the listening event.

 

Switch over to the NewsAggregator.Digg project and add a reference to the NewsAggregator.Infrastructure (in the same way you’ve just done this to the NewsAggregator.Search above)

 

In the DiggSearchResultsViewModel remove the previous dummy search data, and add an event aggregator event to the constructor, and subscribe to the the OnSearchEvent which is a local event just created to process the title.

 

Visual Basic

Imports System.Collections.ObjectModel

Imports Microsoft.Practices.Composite.Events

Imports NewsAggregator.Infrastructure

 

Public Class DiggSearchResultsViewModel

 

    Private _Stories As ObservableCollection(Of DiggStory)

    Private diggService As IDiggService

 

    Public Property Stories() As ObservableCollection(Of DiggStory)

        Get

            Return _Stories

        End Get

        Private Set(ByVal value As ObservableCollection(Of DiggStory))

            _Stories = value

        End Set

    End Property

 

    Public ReadOnly Property HeaderInfo() As String

        Get

            Return "Digg Search Results"

        End Get

    End Property

 

    Public Sub New(ByVal diggService As IDiggService, ByVal eventAggregator As IEventAggregator)

 

        Stories = New ObservableCollection(Of DiggStory)()

        Me.diggService = diggService

        eventAggregator.GetEvent(Of SearchEvent).Subscribe(AddressOf OnSearchEvent)

    End Sub

 

    Public Sub OnSearchEvent(ByVal title As String)

        Me.diggService.BeginSearch(title, AddressOf OnSearchComplete)

    End Sub

 

    Private Sub OnSearchComplete(ByVal newStories As IEnumerable(Of DiggStory))

        Me.Stories.Clear()

        For Each diggStory In newStories

            Me.Stories.Add(diggStory)

        Next

    End Sub

End Class

 

C#

using System.Collections.ObjectModel;

using System.Collections.Generic;

using Microsoft.Practices.Composite.Events;

using NewsAggregator.Infrastructure;

 

namespace NewsAggregator.Digg

{

    public class DiggSearchResultsViewModel

    {

        private IDiggService diggService;

        public DiggSearchResultsViewModel(IDiggService diggService, IEventAggregator eventAggregator)

        {

            Stories = new ObservableCollection<DiggStory>();

            this.diggService = diggService;

 

            eventAggregator.GetEvent<SearchEvent>().Subscribe(OnSearchEvent);          

        }

 

        public void OnSearchEvent(string title)

        {

            this.diggService.BeginSearch(title, OnSearchComplete);

        }

 

        public string HeaderInfo

        {

            get { return "Digg Search Results"; }

        }

        private void OnSearchComplete(IEnumerable<DiggStory> newStories)

        {

            this.Stories.Clear();

 

            foreach (var diggStory in newStories)

            {

                this.Stories.Add(diggStory);

            }

        }

 

        public ObservableCollection<DiggStory> Stories

        {

            get;

            private set;

        }

    }

}

 

Important: Notice that the OnSearchEvent is a public method. This is because Prism does not keep a strong reference to that particular event, this help prevent problems with garbage collection, so it doesn’t prevent your ViewModel being garbage collected for example if the ViewModel is no longer in use. If you do chose to make this private you will need to remember to unsubscribe whenever your ViewModel is no longer in use.

If you run the application, and enter”baseball” you should find that the application can still search base. Try entering a “football” search and you should get football results

FootBallSearch

You should now be able to develop the Twitter client in exactly the same was and add that as a module to the module catalogue in the shell and have that just work.

The complete source code for the 4 part series is available here

Building a Composite WPF and Silverlight Application with Prism – Part 3

Welcome to this four part series on building a WPF and Silverlight application with Prism. The previous parts are

Building a Composite WPF and Silverlight Application with Prism – Part 1

Building a Composite WPF and Silverlight Application with Prism – Part 2

In this third tutorial, we will create a Digg search view using the Model-View-View-Model (MVVM) pattern, create the Digg search service, and finally demonstrate how to use dependency injection to “inject” views into the View Models.

This tutorial is in both C# and Visual Basic, but when creating projects in Visual Studio, the images I may use may be C# templates for example, but you should be able to do exactly the same in Visual Basic and vica-versa. It avoids the repetition of posting two images with “Open C# Silverlight Application” and “Open Visual Basic Application”, when the Visual Studio templates are the same – bar the language. I will however, post code samples in both languages

Implementing the View using MVVM

The first thing to do is to separate the View from the View Model. We do this because

  1. View Models are far much more testable
  2. It works well with re-styling

Add another class called DiggSearchResultsViewModel. The View Model typically has all the properties that you want to bind to. Within this View Model we will have a DiggStory object, so add another class called DiggStory

Projects

In this DiggStory add the following properties

Visual Basic

Public Class DiggStory

    Public Class DiggStory

        Private _Id As Integer

        Public Property Id() As Integer

            Get

                Return _Id

            End Get

            Set(ByVal value As Integer)

                _Id = value

            End Set

        End Property

        Private _Title As String

        Public Property Title() As String

            Get

                Return _Title

            End Get

            Set(ByVal value As String)

                _Title = value

            End Set

        End Property

        Private _Description As String

        Public Property Description() As String

            Get

                Return _Description

            End Get

            Set(ByVal value As String)

                _Description = value

            End Set

        End Property

        Private _NumDiggs As Integer

        Public Property NumDiggs() As Integer

            Get

                Return _NumDiggs

            End Get

            Set(ByVal value As Integer)

                _NumDiggs = value

            End Set

        End Property

        Private _HrefLink As Uri

        Public Property HrefLink() As Uri

            Get

                Return _HrefLink

            End Get

            Set(ByVal value As Uri)

                _HrefLink = value

            End Set

        End Property

        Private _Thumbnail As String

        Public Property Thumbnail() As String

            Get

                Return _Thumbnail

            End Get

            Set(ByVal value As String)

                _Thumbnail = value

            End Set

        End Property

        Private _UserName As String

        Public Property UserName() As String

            Get

                Return _UserName

            End Get

            Set(ByVal value As String)

                _UserName = value

            End Set

        End Property

    End Class

End Class

C#

using System;

 

namespace NewsAggregator.Digg

{

    public class DiggStory

    {

        public int Id { get; set; }

        public string Title { get; set; }

        public string Description { get; set; }

        public int NumDiggs { get; set; }

        public Uri HrefLink { get; set; }

        public string Thumbnail { get; set; }

        public string UserName { get; set; }

 

    }

}

 

A list of these stories is now required, so in the DiggSearchResultsViewModel create the following collection, and add a dummy story in the constructor of the form (note we only need the title here). The ObvervableCollection provides a way to track changes make to the collection.

 

Visual Basic

Imports System.Collections.ObjectModel

Public Class DiggSearchResultsViewModel

    Public Sub New()

        Stories = New ObservableCollection(Of DiggStory)()

 

        Dim story As New DiggStory()

        story.Title = "I am here, Digg it"

        Stories.Add(story)

    End Sub

 

    Private _Stories As ObservableCollection(Of DiggStory)

    Public Property Stories() As ObservableCollection(Of DiggStory)

        Get

            Return _Stories

        End Get

        Private Set(ByVal value As ObservableCollection(Of DiggStory))

            _Stories = value

        End Set

    End Property

End Class

C#

using System.Collections.ObjectModel;

 

namespace NewsAggregator.Digg

{

    public class DiggSearchResultsViewModel

    {

        public DiggSearchResultsViewModel()

        {

            Stories = new ObservableCollection<DiggStory>();

            Stories.Add(new DiggStory(){Title = "I am here, Digg it"});    

        }

 

        public ObservableCollection<DiggStory> Stories

        {

            get;

            private set;

        }

    }

}

Connecting the Model with the View Model

To connect these together we will use constructor injection again. In the DiggSearchResultsView controls constructor add the ViewModel and set the DataContext object of the control to the view model.

Visual Basic

Partial Public Class DiggSearchResultsView

    Inherits UserControl

    Public Sub New(ByVal viewModel As DiggSearchResultsViewModel)

        InitializeComponent()

        Me.DataContext = viewModel

    End Sub

End Class

C#

namespace NewsAggregator.Digg

{

    public partial class DiggSearchResultsView : UserControl

    {

        public DiggSearchResultsView(DiggSearchResultsViewModel viewModel)

        {

            InitializeComponent();

            this.DataContext = viewModel;

        }

    }

}

 

In the XAML for the control, delete the TextBlock with the message in it, and add a ListBox instead

 

<UserControl x:Class="NewsAggregator.Digg.DiggSearchResultsView"

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

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

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

        <ListBox Name="storiesList" ItemsSource="{Binding Stories}"></ListBox>

    </Grid>

</UserControl>

Click F5 to run the program and you should have the following

DiggStory

Add a DataTemplate to the ListBox to format the Stories (or story in this case). You will see that there is quite a bit of XAML, but most of it is to do with styling

<UserControl x:Class="NewsAggregator.Digg.DiggSearchResultsView"

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

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

 

    <UserControl.Resources>

        <Style x:Key="StoriesList" TargetType="ListBox">

            <Setter Property="Margin" Value="5"/>

            <Setter Property="Grid.Row" Value="1"/>

        </Style>

 

        <Style x:Key="DiggPanel" TargetType="StackPanel">

            <Setter Property="Margin" Value="10"/>

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

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

            <Setter Property="Background">

                <Setter.Value>

                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                        <GradientStop Color="#FFFFF098"/>

                        <GradientStop Color="#FFFFF9D4" Offset="1"/>

                    </LinearGradientBrush>

                </Setter.Value>

            </Setter>

        </Style>

 

        <Style x:Key="NumDigsBlock" TargetType="TextBlock">

            <Setter Property="HorizontalAlignment" Value="Center"/>

            <Setter Property="FontSize" Value="18"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Foreground" Value="DarkSlateGray"/>

        </Style>

 

        <Style x:Key="NumDigsSubBlock" TargetType="TextBlock">

            <Setter Property="HorizontalAlignment" Value="Center"/>

            <Setter Property="FontSize" Value="14"/>

            <Setter Property="Foreground" Value="DarkSlateGray"/>

        </Style>

 

        <Style x:Key="ThumbNailPreview" TargetType="Image">

            <Setter Property="Margin" Value="7,7,5,5"/>

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

        </Style>

 

        <Style x:Key="TitleBlock" TargetType="TextBlock">

            <Setter Property="FontSize" Value="12"/>

            <Setter Property="TextAlignment" Value="Left"/>

            <Setter Property="VerticalAlignment" Value="Center"/>

        </Style>

 

    </UserControl.Resources>

    <Grid>

        <ListBox x:Name="StoriesList" Style="{StaticResource StoriesList}" ItemsSource="{Binding Stories}">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <StackPanel Orientation="Horizontal">

                        <!– Yellow Digg Panel with NumDiggs–>

                        <StackPanel Style="{StaticResource DiggPanel}" >

 

                            <TextBlock Text="{Binding NumDiggs}" Style="{StaticResource NumDigsBlock}" />

                            <TextBlock Text="diggs" Style="{StaticResource NumDigsSubBlock}" />

 

                        </StackPanel>

 

                        <!– Story Thumbnail Preview –>

                        <Image Source="{Binding ThumbNail}" Style="{StaticResource ThumbNailPreview}" />

 

                        <!– Story Title–>

                        <TextBlock Text="{Binding Title}" Margin="5" Style="{StaticResource TitleBlock}"/>

                    </StackPanel>

 

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

 

    </Grid>

</UserControl>

If you F5 to run the program you should get

DiggClient 

  Adding the Digg Service

First add an interface that will be a contract for the Digg service, call this IDiggService. This Interface will contain one method called BeginSearch that will do two things

  1. It will start the search using the query parameter
  2. It will provide a call-back mechanism for when the search is completed

This is because requests like web service calls in Silverlight must always be carried out asynchronously.

Visual Basic

Public Interface IDiggService

    Sub BeginSearch(ByVal query As String, ByVal SearchCompleteCallback As Action(Of IEnumerable(Of DiggStory)))

End Interface

C#

using System;

using System.Collections.Generic;

 

namespace NewsAggregator.Digg

{

    public interface IDiggService

    {

        void BeginSearch(string query, Action<IEnumerable<DiggStory>> SearchCompleteCallback);     

    }

}

You can now either implement the Service or View, but I will start with the view first.

Implementing the View

In the constructor for the DiggSearchResultsViewModel add a reference to IDiggService. Here we will then perform a dummy query for “baseball”. When this query is complete it will return some stories (hopefully) pertaining to baseball. These then need to be added to a list in the OnSearchComplete method. The only thing you need to do to view the stories returned from the list is to add them to the Stories already defined.

Visual Basic

Imports System.Collections.ObjectModel

Public Class DiggSearchResultsViewModel

 

    Private _Stories As ObservableCollection(Of DiggStory)

    Private diggService As IDiggService

 

    Public Property Stories() As ObservableCollection(Of DiggStory)

        Get

            Return _Stories

        End Get

        Private Set(ByVal value As ObservableCollection(Of DiggStory))

            _Stories = value

        End Set

    End Property

 

    Public ReadOnly Property HeaderInfo() As String

        Get

            Return "Digg Search Results"

        End Get

    End Property

 

    Public Sub New(ByVal diggService As IDiggService)

 

        Stories = New ObservableCollection(Of DiggStory)()

 

        Dim dummyStory As New DiggStory()

        dummyStory.Title = "I am here, Digg it"

 

        Stories.Add(dummyStory)

 

        Me.diggService = diggService

        Me.diggService.BeginSearch("baseball", AddressOf OnSearchComplete)

    End Sub

 

    Private Sub OnSearchComplete(ByVal newStories As IEnumerable(Of DiggStory))

        Me.Stories.Clear()

        For Each diggStory In newStories

            Me.Stories.Add(diggStory)

        Next

    End Sub

End Class

C#

using System.Collections.ObjectModel;

using System.Collections.Generic;

 

namespace NewsAggregator.Digg

{

    public class DiggSearchResultsViewModel

    {

        private IDiggService diggService;

        public DiggSearchResultsViewModel(IDiggService diggService)

        {

            Stories = new ObservableCollection<DiggStory>();

            Stories.Add(new DiggStory(){Title = "I am here, Digg it"});

            this.diggService = diggService;

 

            this.diggService.BeginSearch("baseball", OnSearchComplete);

        }

 

        private void OnSearchComplete(IEnumerable<DiggStory> newStories)

        {

            this.Stories.Clear();

 

            foreach (var diggStory in newStories)

            {

                this.Stories.Add(diggStory);

            }

        }

 

        public ObservableCollection<DiggStory> Stories

        {

            get;

            private set;

        }

    }

}

Implementing the Service

In the Digg project add a reference to System.XML.Linq because I am calling a web service and am getting an XML document back (the RSS feed).

Add a new class called DiggService to the project that implements IDiggService

Visual Basic

Option Explicit On

Option Strict On

Imports System.Xml.Linq

 

 

 

Public Class DiggService

    Implements IDiggService

    Private searchCompleteCallback As Action(Of IEnumerable(Of DiggStory))

 

    Public Sub BeginSearch(ByVal query As String, ByVal SearchCompleteCallback As Action(Of IEnumerable(Of DiggStory))) Implements IDiggService.BeginSearch

        Me.searchCompleteCallback = SearchCompleteCallback

 

        ‘ Construct Digg REST URL

        Dim diggUrl As String = String.Format("http://services.digg.com/stories/topic/{0}?count=20&appkey=http%3A%2F%2Fscottgu.com", query)

 

        ‘ Initiate Async Network call to Digg

        Dim diggService As New WebClient()

        AddHandler diggService.DownloadStringCompleted, AddressOf diggService_DownloadStringCompleted

        diggService.DownloadStringAsync(New Uri(diggUrl))

 

    End Sub

 

    Sub diggService_DownloadStringCompleted(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs)

        searchCompleteCallback(BuildStories(e))

    End Sub

 

 

    Private Function BuildStories(ByVal e As DownloadStringCompletedEventArgs) As IEnumerable(Of DiggStory)

        If e.[Error] IsNot Nothing Then

            Return New List(Of DiggStory)(New DiggStory() {New DiggStory() With {.Title = e.[Error].Message}})

        End If

 

        Dim xmlStories As XDocument = XDocument.Parse(e.Result)

 

 

        Dim stories = From story In xmlStories.Descendants("story") _

                        Where story.Element("thumbnail") IsNot Nothing AndAlso _

                              Not story.<thumbnail>.Value.EndsWith(".gif") _

                        Select New DiggStory() With _

                        { _

                            .Id = CInt(story.@id), _

                            .Title = story.<title>.Value.Trim(), _

                            .Description = story.<description>.Value.Trim(), _

                            .ThumbNail = story.<thumbnail>.@src, _

                            .HrefLink = New Uri(story.@link), _

                            .NumDiggs = CInt(story.@diggs), _

                            .UserName = story.<user>.Value.Trim() _

                        }

        Return stories

    End Function

 

End Class

 

C#

using System;

using System.Net;

using System.Xml.Linq;

using System.Collections.Generic;

using System.Linq;

 

namespace NewsAggregator.Digg

{

    public class DiggService : IDiggService

    {

        public void BeginSearch(string query, Action<IEnumerable<DiggStory>> SearchCompleteCallback)

        {

            // Construct Digg REST URL

            string diggUrl = String.Format("http://services.digg.com/stories/topic/{0}?count=20&appkey=http%3A%2F%2Fscottgu.com", query);

 

            // Initiate Async Network call to Digg

            WebClient diggService = new WebClient();

            diggService.DownloadStringCompleted += (sender, e) => SearchCompleteCallback(BuildStories(e));

            diggService.DownloadStringAsync(new Uri(diggUrl));

        }

 

        private IEnumerable<DiggStory> BuildStories(DownloadStringCompletedEventArgs e)

        {

            if (e.Error != null)

            {

                return new List<DiggStory> { new DiggStory() { Title = e.Error.Message } };

            }

 

            XDocument xmlStories = XDocument.Parse(e.Result);

 

            var stories = from story in xmlStories.Descendants("story")

                          where story.Element("thumbnail") != null &&

                                !story.Element("thumbnail").Attribute("src").Value.EndsWith(".gif")

                          select new DiggStory

                          {

                              Id = (int)story.Attribute("id"),

                              Title = ((string)story.Element("title")).Trim(),

                              Description = ((string)story.Element("description")).Trim(),

                              ThumbNail = (string)story.Element("thumbnail").Attribute("src").Value,

                              HrefLink = new Uri((string)story.Attribute("link")),

                              NumDiggs = (int)story.Attribute("diggs"),

                              UserName = (string)story.Element("user").Attribute("name").Value,

                          };

 

            return stories;

        }

    }

}

 

In the DiggModule register this search query in the UnityContainer. To acheive this, create a private IUnityContainer variable called container and add this to the constructor. You can then register this in the Initialize method. The ContainerControlledLifetimeManager class just indicates that the service should be a Singleton.

 

Visual Basic

Imports Microsoft.Practices.Composite.Modularity

Imports Microsoft.Practices.Composite.Regions

Imports Microsoft.Practices.Unity

 

Public Class DiggModule

    Implements IModule

 

    Private regionManager As IRegionManager

    Private container As IUnityContainer

 

    Public Sub New(ByVal regionManager As IRegionManager, ByVal container As IUnityContainer)

        Me.regionManager = regionManager

        Me.container = container

    End Sub

 

    Public Sub Initialize() Implements Microsoft.Practices.Composite.Modularity.IModule.Initialize

        Me.container.RegisterType(Of IDiggService, DiggService)(New ContainerControlledLifetimeManager())

        Me.regionManager.RegisterViewWithRegion("ResultsRegion", GetType(DiggSearchResultsView))

    End Sub

End Class

 

C#

using Microsoft.Practices.Composite.Modularity;

using Microsoft.Practices.Composite.Regions;

using Microsoft.Practices.Unity;

 

 

namespace NewsAggregator.Digg

{

    public class DiggModule : IModule

    {

        private IRegionManager regionManager;

        private IUnityContainer container;

 

        public DiggModule(IRegionManager regionManager, IUnityContainer container)

        {

            this.regionManager = regionManager;

            this.container = container;

        }

 

        #region IModule Members

 

        public void Initialize()

        {

            this.container.RegisterType<IDiggService, DiggService>(new ContainerControlledLifetimeManager());

            this.regionManager.RegisterViewWithRegion("ResultsRegion", typeof(DiggSearchResultsView));

        }

 

        #endregion

    }

}

If you run the project you should a view with live data

ConnectedToService

If you look carefully at the tab at the top of the shell you will see that there is not title for the shell so a way is needed to communicate title or header information back to the Shell

Header Information

There is a convention to follow when providing this information, and that is for the View Model to provide this information to the Shell Owner can look for this information. Add a new Property into the DiggSearchResultsViewModel called HeaderInfo.

Visual Basic

Imports System.Collections.ObjectModel

Public Class DiggSearchResultsViewModel

 

    Private _Stories As ObservableCollection(Of DiggStory)

    Private diggService As IDiggService

 

    Public Property Stories() As ObservableCollection(Of DiggStory)

        Get

            Return _Stories

        End Get

        Private Set(ByVal value As ObservableCollection(Of DiggStory))

            _Stories = value

        End Set

    End Property

 

    Public ReadOnly Property HeaderInfo() As String

        Get

            Return "Digg Search Results"

        End Get

    End Property

 

    Public Sub New(ByVal diggService As IDiggService)

        Stories = New ObservableCollection(Of DiggStory)()

 

        Dim story As New DiggStory()

        story.Title = "I am here, Digg it"

        Stories.Add(story)

 

        Me.diggService = diggService

        Me.diggService.BeginSearch("baseball", AddressOf OnSearchComplete)

    End Sub

 

    Private Sub OnSearchComplete(ByVal newStories As IEnumerable(Of DiggStory))

        Me.Stories.Clear()

 

        For Each diggStory In newStories

            Me.Stories.Add(diggStory)

        Next

    End Sub

End Class

C#

using System.Collections.ObjectModel;

using System.Collections.Generic;

 

namespace NewsAggregator.Digg

{

    public class DiggSearchResultsViewModel

    {

        private IDiggService diggService;

        public DiggSearchResultsViewModel(IDiggService diggService)

        {

            Stories = new ObservableCollection<DiggStory>();

            Stories.Add(new DiggStory(){Title = "I am here, Digg it"});

            this.diggService = diggService;

 

            this.diggService.BeginSearch("baseball", OnSearchComplete);

        }

 

        public string HeaderInfo

        {

            get { return "Digg Search Results"; }

        }

        private void OnSearchComplete(IEnumerable<DiggStory> newStories)

        {

            this.Stories.Clear();

 

            foreach (var diggStory in newStories)

            {

                this.Stories.Add(diggStory);

            }

        }

 

        public ObservableCollection<DiggStory> Stories

        {

            get;

            private set;

        }

    }

}

Open up the Shell.xaml and add the following markup in the tab regions section. Note in WPF this tab property is available to databind to directly, but this is not available in Silverlight.

<UserControl xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" x:Class="NewsAggregator.Shell.Shell"

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

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

      xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation">

    <UserControl.Resources>

        <Style x:Key="TopGrid" TargetType="Grid">

            <Setter Property="Background" Value="#FF5C7590" />

        </Style>

    </UserControl.Resources>

    <Grid Style="{StaticResource TopGrid}">

        <Grid.RowDefinitions>

            <RowDefinition Height="auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <ContentControl Regions:RegionManager.RegionName="SearchRegion" Grid.Row="0" Margin="2" />

        <basics:TabControl Regions:RegionManager.RegionName="ResultsRegion" Grid.Row="1" Margin="3">

            <Regions:TabControlRegionAdapter.ItemContainerStyle>

                <Style TargetType="basics:TabItem">

                    <Setter Property="HeaderTemplate">

                        <Setter.Value>

                            <DataTemplate>

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

                            </DataTemplate>

                        </Setter.Value>

                    </Setter>

                </Style>

            </Regions:TabControlRegionAdapter.ItemContainerStyle>

        </basics:TabControl>

 

    </Grid>

</UserControl>

If you run the program you should have

SearchResults

That wraps up this penultimate tutorial, in the fourth and final tutorial we will add a searchbox, and show how this can be added in a decoupled fashion.

The complete source code for the 4 part series is available here