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&#8221;

   xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”&gt;

    <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&#8221;

   xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

   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 (Download the WPF Silverlight Prism Folder)

15 thoughts on “Building a Composite WPF and Silverlight Application with Prism – Part 4

  1. hi,

    A very comprehensive and useful walk through, it really went right throughout, and I would recommend all those who have just started their work Using Prism 2 that this is a very powerful, encouraging and fast track for their learning.

    But, I would ask you, if you could manage to write something that elaborate Model-View-ViewModel design pattern, because i’m still not comfortable with the design pattern.

    Anyhow, I really appreciate your work, Thanks.

    Usman Afzal

  2. Hello Usman,

    Well it’s good to see someone has actually found this useful, I do know that a lot of people like the MVVM pattern, and others don’t. Microsoft Patterns & Practices actually favour the Model View Presenter (MVP) pattern, though you could even use the Model View Controller (MVC) pattern in ASP.NET.

    I don’t think that there is a right way or a wrong way, as there are a great number of ways to achieve the same or similar results, though if you use the MVVM pattern, and you have to maintain code written by someone else, it is easier because it follows a similar hence familiar pattern.

    I think by the time Visual Studio 2010 comes out (they have a MVVM style template), the tools themselves will make it easier to create and manage these types of applications and design patterns, things like the Entity Framework will support the paterrn more easily than it does at the moment.

  3. @Alex I have now published the source as requested. Just scroll down to the bottom of any of the tutorials, and you will find a link to the source there.

    Thanks,

    Ira

  4. Great Work. I saw the Videos in Channel 9 too. They were great too. Thanks for the post. I am sure many starters would be greatly benefited by this.

  5. One Doubt… I would want to load a Module on Demand.

    I have a LoginRegion and I have LoginModule that Displays Username, Password and Hyperlink for “Forgot Password” option.

    I also have a ForgotPassword Module, Who’s “View” UI has a Text box that takes the username and Email Address.

    Currently I am able to Load the LoginModule in the LoginRegion. Now when the user clicks the “Forgot password” Hyperlink in the LoginView, I want to unload the LoginModule from the Login Region and reload the ForgotPassword Module onto the same (LoginRegion).

    Currently in the GetCatalog() I register both the LoginModule and the ForgotPassword Module. The ForgotPassword Module overlaps the LoginModule.

    Is there a way around?

    Excuse me if my question is very basic but I am very new to Prism.

  6. I’ve tried the demo from the Channel9. I’ve noticed one problem. The HeaderInfo in TabControl is not shown. I’m using Silverlight 3.
    I’m intending to use this functionality in my own app, so any solutions?

    By the way, excellent example of using composite application practise.

  7. Hello mitdej,

    Have you tried the source code that I’ve posted at the bottom of each post? If you look at this specific post, you will see that “header” information is drawn in the TabControl?

  8. This is an awesome guide – thanks! I just started playing with prism today, and this has proved to be an excellent resource.

    Cheers,
    Charles

  9. Ira,
    Excellant walkthrough !!!
    Appreciate much for including the screenshots and the code. This really helps in getting the vision set before you start digging into any code.
    I have two things to understand more before I could be really doing something coding.
    #1
    I am in the same situation where the Login module needs to be replaced with the forgot pwd module, just like what Naveen has mentioned above.
    Is there a workaround to get this thing working with “OnDemand”?

    #2
    Also, Is there a way to inject multiple views within the same region?

    Any working example would be great.
    Thanks in advance for all that you have posted.

    Zullu.

  10. Hi Ira,

    I really want to owe u millions of thanks.The way you explained CAL is awesome.
    I have hardly seen code in vb.net ,mainly code will be in C# and vb.net develpers like me have to convert them.
    U Rock and keep it up.
    We are expecting more artilces from u..

    Cheers,
    Dhivya.

  11. Hi Ira,

    thanks a lot for this nice post. Allow a few questions
    – The source code is not available / link times out. Would you mind pointing us to the correct link ?
    – Now that Silverlight 4 was an ICommand, does it make sense to take advantage of this ?

    Best
    Frank

  12. Hi Frank, sorry for the late reply.

    Yes this post is still quite relevant (I am using it in a live application at present). Silverlight did add commanding subsequent to this post, so you can use that commanding infrastructure instead. I was hoping that the link would be fixed by Microsoft, but this has not happened.

    I have just moved house and have no broadband yet (I am using the WI-FI on my phone), but as soon as I get a chance, I will re-upload the source. I will also update the tutorial to target the current version of Silverlight and Prism in the next week or so.

    Regards,
    Ira

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s