changeset 20:6109bc268b90

Latest
author adminsh@apollo
date Tue, 20 Mar 2012 13:37:46 +0000
parents 09d18d6e5f40
children dfc81f8bb838
files MetroWpf/MetroWpf.sln MetroWpf/MetroWpf/Converters/AbsoluteNumberConverter.cs MetroWpf/MetroWpf/Converters/BoolToServiceRunningTextConverter.cs MetroWpf/MetroWpf/Converters/BoolToSubscribedTextConverter.cs MetroWpf/MetroWpf/Converters/DateTimeToTimeConverter.cs MetroWpf/MetroWpf/Converters/DeltaToIconConverter.cs MetroWpf/MetroWpf/IoCConfiguration.cs MetroWpf/MetroWpf/Locator.cs MetroWpf/MetroWpf/Messages/AuthenticatedUserMessage.cs MetroWpf/MetroWpf/MetroWpf.csproj MetroWpf/MetroWpf/Presentation/Images/DOWN.png MetroWpf/MetroWpf/Presentation/Images/LEVEL.png MetroWpf/MetroWpf/Presentation/Images/UNK.png MetroWpf/MetroWpf/Presentation/Images/UP.png MetroWpf/MetroWpf/Presentation/Login/LoginViewModel.cs MetroWpf/MetroWpf/Presentation/Menu/MenuView.xaml MetroWpf/MetroWpf/Presentation/Menu/MenuViewModel.cs MetroWpf/MetroWpf/Presentation/Splash/splash.png MetroWpf/MetroWpf/Presentation/Stocks/DisplayStockPrice.cs MetroWpf/MetroWpf/Presentation/Stocks/StockTest.xaml MetroWpf/MetroWpf/Presentation/Stocks/StockTest.xaml.cs MetroWpf/MetroWpf/Presentation/Stocks/StocksView.xaml MetroWpf/MetroWpf/Presentation/Stocks/StocksView.xaml.cs MetroWpf/MetroWpf/Presentation/Stocks/StocksViewModel.cs MetroWpf/Stocks.Common/ConfigurationService.cs MetroWpf/Stocks.Common/Core/ExtensionMethods.cs MetroWpf/Stocks.Common/Core/FileSerializer.cs MetroWpf/Stocks.Common/Core/TimedDelegates.cs MetroWpf/Stocks.Common/Events/PriceChangedEventArgs.cs MetroWpf/Stocks.Common/Exceptions/InvalidWebPriceData.cs MetroWpf/Stocks.Common/Factory.cs MetroWpf/Stocks.Common/Fakes/FakeWebClientShim.cs MetroWpf/Stocks.Common/IConfigurationService.cs MetroWpf/Stocks.Common/IStocksService.cs MetroWpf/Stocks.Common/IWebClientShim.cs MetroWpf/Stocks.Common/Models/Company.cs MetroWpf/Stocks.Common/Models/Price.cs MetroWpf/Stocks.Common/Models/Quote.cs MetroWpf/Stocks.Common/Models/SummaryStats.cs MetroWpf/Stocks.Common/Models/WebRequestStats.cs MetroWpf/Stocks.Common/Properties/AssemblyInfo.cs MetroWpf/Stocks.Common/Stocks.Common.csproj MetroWpf/Stocks.Common/WebClientShim.cs MetroWpf/Stocks.Service/AssemblyInit.cs MetroWpf/Stocks.Service/Properties/AssemblyInfo.cs MetroWpf/Stocks.Service/Stocks.Service.csproj MetroWpf/Stocks.Service/StocksService.cs MetroWpf/Stocks.UI/App.xaml MetroWpf/Stocks.UI/App.xaml.cs MetroWpf/Stocks.UI/Converters/AbsoluteNumberConverter.cs MetroWpf/Stocks.UI/Converters/BoolToServiceRunningTextConverter.cs MetroWpf/Stocks.UI/Converters/BoolToSubscribedTextConverter.cs MetroWpf/Stocks.UI/Converters/DateTimeToTimeConverter.cs MetroWpf/Stocks.UI/Converters/DeltaToIconConverter.cs MetroWpf/Stocks.UI/DisplayStockPrice.cs MetroWpf/Stocks.UI/Locator.cs MetroWpf/Stocks.UI/Properties/AssemblyInfo.cs MetroWpf/Stocks.UI/Properties/Resources.Designer.cs MetroWpf/Stocks.UI/Properties/Resources.resx MetroWpf/Stocks.UI/Properties/Settings.Designer.cs MetroWpf/Stocks.UI/Properties/Settings.settings MetroWpf/Stocks.UI/Stocks.UI.csproj MetroWpf/Stocks.UI/StocksView.xaml MetroWpf/Stocks.UI/StocksView.xaml.cs MetroWpf/Stocks.UI/StocksViewModel.cs MetroWpf/packages/repositories.config
diffstat 66 files changed, 2661 insertions(+), 370 deletions(-) [+]
line wrap: on
line diff
--- a/MetroWpf/MetroWpf.sln	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf.sln	Tue Mar 20 13:37:46 2012 +0000
@@ -9,6 +9,10 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetroWpf.Xaml", "MetroWpf.Xaml\MetroWpf.Xaml.csproj", "{A5D99423-4BAE-4FC0-A0CB-F7238EC2C402}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stocks.Service", "Stocks.Service\Stocks.Service.csproj", "{47F54122-5381-48D8-ACF7-72BBE0353511}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stocks.Common", "Stocks.Common\Stocks.Common.csproj", "{847365D2-E27B-44C3-8DF4-B749D9FA65D7}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -59,6 +63,26 @@
 		{A5D99423-4BAE-4FC0-A0CB-F7238EC2C402}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{A5D99423-4BAE-4FC0-A0CB-F7238EC2C402}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{A5D99423-4BAE-4FC0-A0CB-F7238EC2C402}.Release|x86.ActiveCfg = Release|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Release|Any CPU.Build.0 = Release|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{47F54122-5381-48D8-ACF7-72BBE0353511}.Release|x86.ActiveCfg = Release|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{847365D2-E27B-44C3-8DF4-B749D9FA65D7}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Converters/AbsoluteNumberConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace MetroWpf.Converters
+{
+  public class AbsoluteNumberConverter : IValueConverter
+  {
+    #region IValueConverter Members
+
+    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+      return Math.Abs((decimal) value);
+    }
+
+    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+      throw new NotImplementedException();
+    }
+
+    #endregion
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Converters/BoolToServiceRunningTextConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace MetroWpf.Converters
+{
+    public class BoolToServiceRunningTextConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return (bool) value ? "Service Running" : "Service Stopped";
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Converters/BoolToSubscribedTextConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace MetroWpf.Converters
+{
+    public class BoolToSubscribedTextConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return (bool) value ? "Subscribed" : "Unsubscribed";
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Converters/DateTimeToTimeConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,24 @@
+using System;
+using System.Windows.Data;
+
+namespace MetroWpf.Converters
+{
+    public class DateTimeToTimeConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            string dateTimeString = ((DateTime) value).ToString("HH:mm:ss.ffff");
+
+            return dateTimeString;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Converters/DeltaToIconConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,46 @@
+using System;
+using System.Windows.Data;
+using System.Windows.Media.Imaging;
+
+namespace MetroWpf.Converters
+{
+    public class DeltaToIconConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            string uri;
+            BitmapImage image;
+            decimal delta;
+            string file = "UNK";
+
+            try
+            {
+                delta = (decimal)value;
+                {
+                    if (delta > 0)
+                        file = "UP";
+                    else if (delta < 0)
+                        file = "DOWN";
+                    else
+                        file = "LEVEL";
+                }
+            }
+            finally
+            {
+                uri = string.Format("../Images/{0}.png", file);
+                image = new BitmapImage(new Uri(uri, UriKind.Relative));
+            }
+
+            return image;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- a/MetroWpf/MetroWpf/IoCConfiguration.cs	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/IoCConfiguration.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -5,34 +5,50 @@
 using MetroWpf.Presentation.Settings;
 using MetroWpf.Presentation.Login;
 using MetroWpf.Presentation.About;
+using MetroWpf.Presentation.Stocks;
 using MetroWpf.Presentation.UserProfile;
 using MetroWpf.Presentation.Menu;
 using MetroWpf.Presentation.Shell;
+using Stocks.Common;
+using Stocks.Service;
 
 namespace MetroWpf
 {
-  public class IoCConfiguration
-  {
-    private static void RegisterCoreServices()
+    public class IoCConfiguration
     {
-      SimpleIoc.Default.Register<IMessenger, Messenger>();
-      SimpleIoc.Default.Register<IWpfApplication, WpfApplication>();
-      SimpleIoc.Default.Register<MainWindowViewModel>(); 
-      SimpleIoc.Default.Register<MenuViewModel>();
-      SimpleIoc.Default.Register<LoginViewModel>();
-      SimpleIoc.Default.Register<UserProfileViewModel>();
-      SimpleIoc.Default.Register<SettingsViewModel>();
-      SimpleIoc.Default.Register<AboutViewModel>();
+        private static void RegisterCoreServices()
+        {
+            // view model services
+
+            // STOCKS
+            SimpleIoc.Default.Register<Stocks.Common.IConfigurationService, Stocks.Common.ConfigurationService>();
+            SimpleIoc.Default.Register<IWebClientShim, WebClientShim>();
+            SimpleIoc.Default.Register<IStocksService, StocksService>();
+
+            // core services
+            SimpleIoc.Default.Register<IMessenger, Messenger>();
+            SimpleIoc.Default.Register<IWpfApplication, WpfApplication>(); 
+
+            // view models
+            SimpleIoc.Default.Register<StocksViewModel>();
+            
+            SimpleIoc.Default.Register<MainWindowViewModel>();
+            SimpleIoc.Default.Register<MenuViewModel>();
+            SimpleIoc.Default.Register<LoginViewModel>();
+            SimpleIoc.Default.Register<UserProfileViewModel>();
+            SimpleIoc.Default.Register<SettingsViewModel>();
+            SimpleIoc.Default.Register<AboutViewModel>();
+
+        }
+
+        public static void RegisterDesignTimeServices()
+        {
+            RegisterCoreServices();
+        }
+
+        public static void RegisterRuntimeServices()
+        {
+            RegisterCoreServices();
+        }
     }
-
-    public static void RegisterDesignTimeServices()
-    {
-      RegisterCoreServices();
-    }
-
-    public static void RegisterRuntimeServices()
-    {
-      RegisterCoreServices();
-    }
-  }
 }
--- a/MetroWpf/MetroWpf/Locator.cs	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/Locator.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -3,6 +3,7 @@
 using MetroWpf.Presentation.Shell;
 using MetroWpf.Presentation.Settings;
 using MetroWpf.Presentation.Login;
+using MetroWpf.Presentation.Stocks;
 using MetroWpf.Presentation.UserProfile;
 using MetroWpf.Presentation.About;
 using MetroWpf.Presentation.Menu;
@@ -21,6 +22,7 @@
       else
       {
         // Create run time services and view models
+        IoCConfiguration.RegisterRuntimeServices();
       }
     }
 
@@ -53,5 +55,10 @@
     {
       get { return SimpleIoc.Default.GetInstance<AboutViewModel>(); }
     }
+
+    public StocksViewModel StocksViewModel
+    {
+        get { return SimpleIoc.Default.GetInstance<StocksViewModel>(); }
+    }
   }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Messages/AuthenticatedUserMessage.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,9 @@
+using GalaSoft.MvvmLight.Messaging;
+
+namespace MetroWpf.Messages
+{
+    public class UserAuthenticatedMessage : MessageBase
+    {
+        public string UserId { get; set; }
+    }
+}
--- a/MetroWpf/MetroWpf/MetroWpf.csproj	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/MetroWpf.csproj	Tue Mar 20 13:37:46 2012 +0000
@@ -52,9 +52,15 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\Libs\CommonServiceLocator.1.0\lib\NET35\Microsoft.Practices.ServiceLocation.dll</HintPath>
     </Reference>
+    <Reference Include="Ninject">
+      <HintPath>..\Libs\Ninject.2.2.1.4\lib\net40-Client\Ninject.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Data" />
+    <Reference Include="System.Reactive, Version=1.0.10621.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\Libs\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
+    </Reference>
     <Reference Include="System.Windows.Interactivity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
       <HintPath>..\packages\Caliburn.Micro.1.3.1\lib\net40\System.Windows.Interactivity.dll</HintPath>
     </Reference>
@@ -79,7 +85,21 @@
       <DependentUpon>App.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Converters\AbsoluteNumberConverter.cs" />
+    <Compile Include="Converters\BoolToServiceRunningTextConverter.cs" />
+    <Compile Include="Converters\BoolToSubscribedTextConverter.cs" />
+    <Compile Include="Converters\DateTimeToTimeConverter.cs" />
+    <Compile Include="Converters\DeltaToIconConverter.cs" />
+    <Compile Include="Messages\AuthenticatedUserMessage.cs" />
     <Compile Include="Messages\NavigationMessage.cs" />
+    <Compile Include="Presentation\Stocks\DisplayStockPrice.cs" />
+    <Compile Include="Presentation\Stocks\StocksView.xaml.cs">
+      <DependentUpon>StocksView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Presentation\Stocks\StocksViewModel.cs" />
+    <Compile Include="Presentation\Stocks\StockTest.xaml.cs">
+      <DependentUpon>StockTest.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Services\Interfaces\INavigationService.cs" />
     <Compile Include="Services\NavigationService.cs" />
     <Compile Include="Presentation\About\AboutView.xaml.cs">
@@ -166,6 +186,14 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
+    <Page Include="Presentation\Stocks\StocksView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Presentation\Stocks\StockTest.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Presentation\UserProfile\UserProfileView.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -192,6 +220,26 @@
       <Project>{A5D99423-4BAE-4FC0-A0CB-F7238EC2C402}</Project>
       <Name>MetroWpf.Xaml</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Stocks.Common\Stocks.Common.csproj">
+      <Project>{847365D2-E27B-44C3-8DF4-B749D9FA65D7}</Project>
+      <Name>Stocks.Common</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Stocks.Service\Stocks.Service.csproj">
+      <Project>{47F54122-5381-48D8-ACF7-72BBE0353511}</Project>
+      <Name>Stocks.Service</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="Presentation\Images\DOWN.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="Presentation\Images\LEVEL.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="Presentation\Images\UNK.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="Presentation\Images\UP.png" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
Binary file MetroWpf/MetroWpf/Presentation/Images/DOWN.png has changed
Binary file MetroWpf/MetroWpf/Presentation/Images/LEVEL.png has changed
Binary file MetroWpf/MetroWpf/Presentation/Images/UNK.png has changed
Binary file MetroWpf/MetroWpf/Presentation/Images/UP.png has changed
--- a/MetroWpf/MetroWpf/Presentation/Login/LoginViewModel.cs	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Login/LoginViewModel.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -1,153 +1,120 @@
-using System;
-using System.Windows;
-using System.ComponentModel;
-using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight;
 using GalaSoft.MvvmLight.Command;
+using GalaSoft.MvvmLight.Messaging;
+using MetroWpf.Messages;
 
 namespace MetroWpf.Presentation.Login
 {
-  /// <summary>
-  /// Login view view model class
-  /// </summary>
-  public sealed class LoginViewModel :
-    ViewModelBase
-  {
-    #region · Data Properties ·
-
     /// <summary>
-    /// Gets or sets whether the form is busy
-    /// </summary>
-    private bool isBusy;
-    public bool IsBusy
-    {
-      get { return isBusy; }
-      set
-      {
-        if (this.isBusy != value)
-        {
-          this.isBusy = value;
-          RaisePropertyChanged("IsBusy");
-          //relay requery?
-        }
-      }
-    }
-
-    /// <summary>
-    /// Gets or sets the user name
+    /// Login view view model class
     /// </summary>
-    private string userId;
-    public string UserId
-    {
-      get { return this.userId; }
-      set
-      {
-        if (this.userId != value)
-        {
-          this.userId = value;
-          RaisePropertyChanged("UserId");
-          LoginCommand.RaiseCanExecuteChanged();
-        }
-      }
-    }
-
-    /// <summary>
-    /// Gets or sets the password
-    /// </summary>
-    private string password;
-    public string Password
-    {
-      get { return this.password; }
-      set
-      {
-        if (this.password != value)
-        {
-          this.password = value;
-          RaisePropertyChanged("Password");
-          LoginCommand.RaiseCanExecuteChanged();
-        }
-      }
-    }
-
-    #endregion
-
-    #region · Constructors ·
-
-    /// <summary>
-    /// Initializes a new instance of the <see cref="LoginViewModel"/> class
-    /// </summary>
-    public LoginViewModel()
-      : base()
+    public sealed class LoginViewModel :
+      ViewModelBase
     {
-      LoginCommand = new RelayCommand(LoginCommandExecute, CanLoginCommandExecute);
-      CloseCommand = new RelayCommand(CloseCommandExecute);
-    }
-
-    #endregion
-
-    #region · Command Actions ·
-
-    #region LoginCommand
-  
-    public RelayCommand LoginCommand { get; set; }
-
-    private void LoginCommandExecute()
-    {
-    }
+        #region · Data Properties ·
 
-    private bool CanLoginCommandExecute() 
-    {
-      if (string.IsNullOrEmpty(UserId) ||
-        string.IsNullOrEmpty(Password))
-        return false;
-
-      return true;
-    }
+        /// <summary>
+        /// Gets or sets whether the form is busy
+        /// </summary>
+        private bool isBusy;
+        public bool IsBusy
+        {
+            get { return isBusy; }
+            set
+            {
+                if (this.isBusy != value)
+                {
+                    this.isBusy = value;
+                    RaisePropertyChanged("IsBusy");
+                    //relay requery?
+                }
+            }
+        }
 
-    #endregion
-
-    #region CloseCommand
-    public RelayCommand CloseCommand { get; set; }
-
-    private void CloseCommandExecute()
-    {
-    }
-    #endregion
-    // should fields be disabled when busy?
+        /// <summary>
+        /// Gets or sets the user name
+        /// </summary>
+        private string userId;
+        public string UserId
+        {
+            get { return this.userId; }
+            set
+            {
+                if (this.userId != value)
+                {
+                    this.userId = value;
+                    RaisePropertyChanged("UserId");
+                    LoginCommand.RaiseCanExecuteChanged();
+                }
+            }
+        }
 
-    //protected override bool CanInquiryData()
-    //{
-    //  return (!String.IsNullOrEmpty(this.UserId) &&
-    //          !String.IsNullOrEmpty(this.Password) &&
-    //          this.ViewMode != ViewModeType.Busy);
-    //}
+        /// <summary>
+        /// Gets or sets the password
+        /// </summary>
+        private string password;
+        public string Password
+        {
+            get { return this.password; }
+            set
+            {
+                if (this.password != value)
+                {
+                    this.password = value;
+                    RaisePropertyChanged("Password");
+                    LoginCommand.RaiseCanExecuteChanged();
+                }
+            }
+        }
 
-    //protected override void OnInquiryAction(InquiryActionResult<UserLogin> result)
-    //{
-    //  result.Data = this.Entity;
-    //  result.Result = InquiryActionResultType.DataFetched;
-    //}
+        #endregion
+
+        #region · Constructors ·
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LoginViewModel"/> class
+        /// </summary>
+        public LoginViewModel()
+            : base()
+        {
+            LoginCommand = new RelayCommand(LoginCommandExecute, CanLoginCommandExecute);
+            CloseCommand = new RelayCommand(CloseCommandExecute);
+        }
+
+        #endregion
 
-    //protected override void OnInquiryActionComplete(InquiryActionResult<UserLogin> result)
-    //{
-    //  if (result.Result == InquiryActionResultType.DataFetched)
-    //  {
-    //    Channel<AuthenticationInfo>.Public.OnNext(
-    //        new AuthenticationInfo
-    //        {
-    //          Action = AuthenticationAction.LoggedIn,
-    //          UserId = this.UserId
-    //        }, true);
+        #region · Command Actions ·
+
+        #region LoginCommand
+
+        public RelayCommand LoginCommand { get; set; }
+
+        private void LoginCommandExecute()
+        {
+            //successful login!
+
+            Messenger.Default.Send(new UserAuthenticatedMessage() { UserId = userId });
+        }
 
-    //    ServiceLocator.GetService<IVirtualDesktopManager>().CloseDialog();
-    //  }
-    //  else if (result.Result == InquiryActionResultType.DataNotFound)
-    //  {
-    //    this.NotificationMessage = "Username and password do not match.";
+        private bool CanLoginCommandExecute()
+        {
+            if (string.IsNullOrEmpty(UserId) ||
+              string.IsNullOrEmpty(Password))
+                return false;
+
+            return true;
+        }
+
+        #endregion
 
-    //    this.ViewMode = ViewModeType.Default;
-    //  }
-    //}
+        #region CloseCommand
+        public RelayCommand CloseCommand { get; set; }
 
-    #endregion
-  }
-}
+        private void CloseCommandExecute()
+        {
+        }
+        #endregion
+
+        #endregion
+    }
+}
\ No newline at end of file
--- a/MetroWpf/MetroWpf/Presentation/Menu/MenuView.xaml	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Menu/MenuView.xaml	Tue Mar 20 13:37:46 2012 +0000
@@ -1,61 +1,62 @@
-<UserControl x:Class="MetroWpf.Presentation.Menu.MenuView"
-      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-      xmlns:login="clr-namespace:MetroWpf.Presentation.Login"
-      xmlns:userprofile="clr-namespace:MetroWpf.Presentation.UserProfile"
-      xmlns:settings="clr-namespace:MetroWpf.Presentation.Settings"
-      xmlns:about="clr-namespace:MetroWpf.Presentation.About"
-      xmlns:converters="clr-namespace:MetroWpf.Xaml.Converters;assembly=MetroWpf.Xaml"
-      mc:Ignorable="d" 
-      DataContext="{Binding MenuViewModel, Source={StaticResource Locator}}">
-  <Grid>
-    <TabControl x:Name="tabHost" SelectedIndex="{Binding SelectedTabIndex, Converter={converters:EnumToIntConverter}}">
+<UserControl x:Class="MetroWpf.Presentation.Menu.MenuView" 
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+             xmlns:about="clr-namespace:MetroWpf.Presentation.About" 
+             xmlns:converters="clr-namespace:MetroWpf.Xaml.Converters;assembly=MetroWpf.Xaml" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:login="clr-namespace:MetroWpf.Presentation.Login"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:settings="clr-namespace:MetroWpf.Presentation.Settings"
+             xmlns:userprofile="clr-namespace:MetroWpf.Presentation.UserProfile"
+             xmlns:Stocks="clr-namespace:MetroWpf.Presentation.Stocks"
+             DataContext="{Binding MenuViewModel, Source={StaticResource Locator}}" 
+             mc:Ignorable="d">
+    <Grid>
+        <TabControl x:Name="tabHost" SelectedIndex="{Binding SelectedTabIndex, Converter={converters:EnumToIntConverter}}">
 
-      <TabItem Header="_Stocks" Visibility="{Binding ShowStocks, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-
-        </StackPanel>
-      </TabItem>
+            <TabItem Header="_Stocks" Visibility="{Binding ShowStocks, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10" HorizontalAlignment="Center">
+                    <Stocks:StockTest/>
+                </StackPanel>
+            </TabItem>
 
-      <TabItem Header="_Rates" Visibility="{Binding ShowFxRates, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
+            <TabItem Header="_Rates" Visibility="{Binding ShowFxRates, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10">
 
-        </StackPanel>
-      </TabItem>
+                </StackPanel>
+            </TabItem>
 
-      <!-- Start of hidden tabs-->
-      <TabItem Name="tabItemLogin" Visibility="{Binding ShowLogin, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-          <login:LoginView/>
-        </StackPanel>
-      </TabItem>
+            <!-- Start of hidden tabs-->
+            <TabItem Name="tabItemLogin" Visibility="{Binding ShowLogin, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10" HorizontalAlignment="Center" VerticalAlignment="Center">
+                    <login:LoginView />
+                </StackPanel>
+            </TabItem>
 
-      <TabItem Name="tabItemUserProfile" Visibility="{Binding ShowUserProfile, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-          <userprofile:UserProfileView />
-        </StackPanel>
-      </TabItem>
+            <TabItem Name="tabItemUserProfile" Visibility="{Binding ShowUserProfile, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10">
+                    <userprofile:UserProfileView />
+                </StackPanel>
+            </TabItem>
 
-      <TabItem Name="tabItemSettings" Visibility="{Binding ShowSettings, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-          <settings:SettingsView />
-        </StackPanel>
-      </TabItem>
+            <TabItem Name="tabItemSettings" Visibility="{Binding ShowSettings, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10">
+                    <settings:SettingsView />
+                </StackPanel>
+            </TabItem>
 
-      <TabItem Name="tabItemAbout" Visibility="{Binding ShowAbout, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-          <about:AboutView />
-        </StackPanel>
-      </TabItem>
+            <TabItem Name="tabItemAbout" Visibility="{Binding ShowAbout, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10">
+                    <about:AboutView />
+                </StackPanel>
+            </TabItem>
 
-      <TabItem Name="tabItemHelp" Visibility="{Binding ShowHelp, Converter={converters:BooleanToVisibilityConverter}}">
-        <StackPanel Margin="25,10">
-          <about:AboutView />
-        </StackPanel>
-      </TabItem>
-      <!-- End of hidden tabs-->
-    </TabControl>
-  </Grid>
+            <TabItem Name="tabItemHelp" Visibility="{Binding ShowHelp, Converter={converters:BooleanToVisibilityConverter}}">
+                <StackPanel Margin="25,10">
+                    <about:AboutView />
+                </StackPanel>
+            </TabItem>
+            <!-- End of hidden tabs-->
+        </TabControl>
+    </Grid>
 </UserControl>
\ No newline at end of file
--- a/MetroWpf/MetroWpf/Presentation/Menu/MenuViewModel.cs	Thu Mar 15 06:59:15 2012 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Menu/MenuViewModel.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -8,178 +8,207 @@
 
 namespace MetroWpf.Presentation.Menu
 {
-  public class MenuViewModel : ViewModelBase
-  {
-    private Screen selectedTabIndex;
-    public Screen SelectedTabIndex
-    {
-      get { return selectedTabIndex; }
-      set
-      {
-        if (selectedTabIndex == value)
-          return;
-
-        selectedTabIndex = value;
-        RaisePropertyChanged("SelectedTabIndex");
-      }
-    }
-
-    private bool showStocks;
-    public bool ShowStocks
+    public class MenuViewModel : ViewModelBase
     {
-      get { return showStocks; }
-      set
-      {
-        if (showStocks == value)
-          return;
+        private Screen selectedTabIndex;
+        public Screen SelectedTabIndex
+        {
+            get { return selectedTabIndex; }
+            set
+            {
+                if (selectedTabIndex == value)
+                    return;
+
+                selectedTabIndex = value;
+                RaisePropertyChanged("SelectedTabIndex");
+            }
+        }
 
-        showStocks = value;
-        RaisePropertyChanged("ShowStocks");
-      }
-    }
+        private bool showStocks;
+        public bool ShowStocks
+        {
+            get { return showStocks; }
+            set
+            {
+                if (showStocks == value)
+                    return;
+
+                showStocks = value;
+                RaisePropertyChanged("ShowStocks");
+            }
+        }
 
-    private bool showFxRates;
-    public bool ShowFxRates
-    {
-      get { return showFxRates; }
-      set
-      {
-        if (showFxRates == value)
-          return;
+        private bool showFxRates;
+        public bool ShowFxRates
+        {
+            get { return showFxRates; }
+            set
+            {
+                if (showFxRates == value)
+                    return;
+
+                showFxRates = value;
+                RaisePropertyChanged("ShowFxRates");
+            }
+        }
 
-        showFxRates = value;
-        RaisePropertyChanged("ShowFxRates");
-      }
-    }
+        private bool showLogin;
+        public bool ShowLogin
+        {
+            get { return showLogin; }
+            set
+            {
+                if (showLogin == value)
+                    return;
+
+                showLogin = value;
+                RaisePropertyChanged("ShowLogin");
+            }
+        }
 
-    private bool showLogin;
-    public bool ShowLogin
-    {
-      get { return showLogin; }
-      set
-      {
-        if (showLogin == value)
-          return;
+        private bool showUserProfile;
+        public bool ShowUserProfile
+        {
+            get { return showUserProfile; }
+            set
+            {
+                if (showUserProfile == value)
+                    return;
 
-        showLogin = value;
-        RaisePropertyChanged("ShowLogin");
-      }
-    }
+                showUserProfile = value;
+                RaisePropertyChanged("ShowUserProfile");
+            }
+        }
 
-    private bool showUserProfile;
-    public bool ShowUserProfile
-    {
-      get { return showUserProfile; }
-      set
-      {
-        if (showUserProfile == value)
-          return;
+        private bool showSettings;
+        public bool ShowSettings
+        {
+            get { return showSettings; }
+            set
+            {
+                if (showSettings == value)
+                    return;
 
-        showUserProfile = value;
-        RaisePropertyChanged("ShowUserProfile");
-      }
-    }
+                showSettings = value;
+                RaisePropertyChanged("ShowSettings");
+            }
+        }
 
-    private bool showSettings;
-    public bool ShowSettings
-    {
-      get { return showSettings; }
-      set
-      {
-        if (showSettings == value)
-          return;
+        private bool showAbout;
+        public bool ShowAbout
+        {
+            get { return showAbout; }
+            set
+            {
+                if (showAbout == value)
+                    return;
 
-        showSettings = value;
-        RaisePropertyChanged("ShowSettings");
-      }
-    }
+                showAbout = value;
+                RaisePropertyChanged("ShowAbout");
+            }
+        }
 
-    private bool showAbout;
-    public bool ShowAbout
-    {
-      get { return showAbout; }
-      set
-      {
-        if (showAbout == value)
-          return;
+        private bool showHelp;
+        public bool ShowHelp
+        {
+            get { return showHelp; }
+            set
+            {
+                if (showHelp == value)
+                    return;
 
-        showAbout = value;
-        RaisePropertyChanged("ShowAbout");
-      }
-    }
+                showHelp = value;
+                RaisePropertyChanged("ShowHelp");
+            }
+        }
 
-    private bool showHelp;
-    public bool ShowHelp
-    {
-      get { return showHelp; }
-      set
-      {
-        if (showHelp == value)
-          return;
+        public MenuViewModel()
+        {
+            Init();
+        }
 
-        showHelp = value;
-        RaisePropertyChanged("ShowHelp");
-      }
-    }
+        private void Init()
+        {
+            Messenger.Default.Register<NavigationMessage>(
+              this,
+              message => ChangeDisplayScreen(message.DisplayScreen));
 
-    public MenuViewModel()
-    {
-      Init();
-    }
+            Messenger.Default.Register<UserAuthenticatedMessage>(
+                this,
+                message => UserAuthenticated(message.UserId));
 
-    private void Init()
-    {
-      Messenger.Default.Register<NavigationMessage>(
-        this,
-        message => ChangeDisplayScreen(message.DisplayScreen));
+            ChangeDisplayScreen(Screen.Login);
+        }
 
-      ChangeDisplayScreen(Screen.Login);
-    }
+        private void UserAuthenticated(string userId)
+        {
+            Messenger.Default.Send(new NavigationMessage() { DisplayScreen= Screen.Stocks });
+        }
 
-    private void ChangeDisplayScreen(Screen screen)
-    {
-      switch (screen)
-      {
-        case Screen.Login:
-          ShowStocks = false;
-          ShowFxRates = false;
-          ShowLogin = true;
-          ShowUserProfile = false;
-          ShowSettings = false;
-          ShowAbout = false;
-          ShowHelp = false;
-          break;
-        case Screen.UserProfile:
-          ShowLogin = false;
-          ShowUserProfile = true;
-          ShowSettings = false;
-          ShowAbout = false;
-          ShowHelp = false;
-          break;
-        case Screen.Settings:
-          ShowLogin = false;
-          ShowUserProfile = false;
-          ShowSettings = true;
-          ShowAbout = false;
-          ShowHelp = false;
-          break;
-        case Screen.About:
-          ShowLogin = false;
-          ShowUserProfile = false;
-          ShowSettings = false;
-          ShowAbout = true;
-          ShowHelp = false;
-          break;
-        case Screen.Help:
-          ShowLogin = false;
-          ShowUserProfile = false;
-          ShowSettings = false;
-          ShowAbout = false;
-          ShowHelp = true;
-          break;
-      }
+        private void ChangeDisplayScreen(Screen screen)
+        {
+            switch (screen)
+            {
+                case Screen.Login:
+                    ShowLogin = true;
+                    
+                    ShowStocks = false;
+                    ShowFxRates = false;
+                    ShowUserProfile = false;
+                    ShowSettings = false;
+                    ShowAbout = false;
+                    ShowHelp = false;
+                    break;
+                case Screen.Stocks:
+                    ShowStocks = true;
+                    ShowFxRates = true;
+                    
+                    ShowLogin = false;
+                    ShowUserProfile = false;
+                    ShowSettings = false;
+                    ShowAbout = false;
+                    ShowHelp = false;
+                    break;
+                case Screen.UserProfile:
+                    ShowUserProfile = true;
+                    
+                    ShowStocks = false;
+                    ShowFxRates = false;
+                    ShowLogin = false;
+                    ShowSettings = false;
+                    ShowAbout = false;
+                    ShowHelp = false;
+                    break;
+                case Screen.Settings:
+                    ShowSettings = true;
+                    
+                    ShowStocks = false;
+                    ShowFxRates = false;
+                    ShowLogin = false;
+                    ShowUserProfile = false;
+                    ShowAbout = false;
+                    ShowHelp = false;
+                    break;
+                case Screen.About:
+                    ShowAbout = true;
+                    
+                    ShowStocks = false;
+                    ShowFxRates = false;
+                    ShowLogin = false;
+                    ShowUserProfile = false;
+                    ShowSettings = false;
+                    ShowHelp = false;
+                    break;
+                case Screen.Help:
+                    ShowLogin = false;
+                    ShowUserProfile = false;
+                    ShowSettings = false;
+                    ShowAbout = false;
+                    ShowHelp = true;
+                    break;
+            }
 
-      SelectedTabIndex = screen;
+            SelectedTabIndex = screen;
+        }
     }
-  }
 }
Binary file MetroWpf/MetroWpf/Presentation/Splash/splash.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/DisplayStockPrice.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,90 @@
+using GalaSoft.MvvmLight;
+using Stocks.Common.Models;
+
+namespace MetroWpf.Presentation.Stocks
+{
+    public class DisplayStockPrice : ObservableObject
+    {
+        public static DisplayStockPrice Create(Price price)
+        {
+            return new DisplayStockPrice()
+                       {
+                           Symbol = price.Symbol,
+                           CurrentPrice = price.CurrentPrice,
+                           PreviousPrice = price.PreviousPrice
+                       };
+        }
+
+        public void Update(Price price)
+        {
+            Symbol = price.Symbol;
+            CurrentPrice = price.CurrentPrice;
+            PreviousPrice = price.PreviousPrice;
+        }
+
+        public const string SymbolPropertyName = "Symbol";
+        private string _symbol;
+        public string Symbol
+        {
+            get { return _symbol; }
+            private set
+            {
+                if (_symbol == value) return;
+                _symbol = value;
+                RaisePropertyChanged(SymbolPropertyName);
+            }
+        }
+
+        public const string CompanyNamePropertyName = "CompanyName";
+        private string _companyName;
+        public string CompanyName
+        {
+            get { return _companyName; }
+            private set
+            {
+                if (_companyName == value) return;
+                _companyName = value;
+                RaisePropertyChanged(CompanyNamePropertyName);
+            }
+        }
+
+        public const string CurrentPricePropertyName = "CurrentPrice";
+        private decimal _currentPrice = 0;
+        public decimal CurrentPrice
+        {
+            get { return _currentPrice; }
+            private set
+            {
+                if (_currentPrice == value) return;
+                _currentPrice = value;
+                RaisePropertyChanged(CurrentPricePropertyName);
+            }
+        }
+
+        public const string PreviousPricePropertyName = "PreviousPrice";
+        private decimal _previousPrice = 0;
+        public decimal PreviousPrice
+        {
+            get { return _previousPrice; }
+            private set
+            {
+                if (_previousPrice == value) return;
+                _previousPrice = value;
+                RaisePropertyChanged(PreviousPricePropertyName);
+            }
+        }
+
+        public const string DeltaPropertyName = "Delta";
+        private decimal _delta = 0;
+        public decimal Delta
+        {
+            get { return _delta; }
+            private set
+            {
+                if (_delta == value) return;
+                _delta = value;
+                RaisePropertyChanged(DeltaPropertyName);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/StockTest.xaml	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,12 @@
+<UserControl x:Class="MetroWpf.Presentation.Stocks.StockTest"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             mc:Ignorable="d" 
+             d:DesignHeight="300" d:DesignWidth="300"
+             DataContext="{Binding StocksViewModel, Source={StaticResource Locator}}">
+    <Grid>
+            
+    </Grid>
+</UserControl>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/StockTest.xaml.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MetroWpf.Presentation.Stocks
+{
+    /// <summary>
+    /// Interaction logic for StockTest.xaml
+    /// </summary>
+    public partial class StockTest : UserControl
+    {
+        public StockTest()
+        {
+            InitializeComponent();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/StocksView.xaml	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,68 @@
+<UserControl x:Class="MetroWpf.Presentation.Stocks.StocksView"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:Converters="clr-namespace:MetroWpf.Converters" mc:Ignorable="d" 
+             d:DesignHeight="100" d:DesignWidth="600"
+             DataContext="{Binding StocksViewModel, Source={StaticResource Locator}}">
+
+    <Grid x:Name="LayoutRoot">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="60" />
+            <RowDefinition Height="20" />
+            <RowDefinition Height="280" />
+            <RowDefinition Height="180" />
+        </Grid.RowDefinitions>
+        <Grid.Resources>
+            <Converters:BoolToServiceRunningTextConverter x:Key="BoolToServiceRunningTextConverter" />
+            <Converters:BoolToSubscribedTextConverter x:Key="BoolToSubscribedTextConverter" />
+            <Converters:DeltaToIconConverter x:Key="DeltaToIconConverter" />
+            <Converters:AbsoluteNumberConverter x:Key="AbsoluteNumberConverter" />
+            <!--<Converters:DateTimeToTimeConverter x:Key="DateTimeToTimeConverter" />-->
+        </Grid.Resources>
+
+        <StackPanel Grid.Row="0" Orientation="Horizontal">
+            <Button x:Name="btnServiceRunning"
+              Width="100"
+              Height="30"
+              HorizontalAlignment="Left" 
+              Content="{Binding ServiceRunning, Converter={StaticResource BoolToServiceRunningTextConverter}}" 
+              Command="{Binding ServiceCommand, Mode=TwoWay}"
+              Margin="5,0,0,0"/>
+            <Button x:Name="btnSubscribe"
+              Width="100"
+              Height="30"
+              Margin="10,0,0,0"
+              HorizontalAlignment="Left" 
+              Content="{Binding Subscribed, Converter={StaticResource BoolToSubscribedTextConverter}}" 
+              Command="{Binding SubscriptionCommand, Mode=TwoWay}" />
+        </StackPanel>
+
+        <StackPanel Grid.Row="1" Orientation="Horizontal">
+            <TextBlock Text="Company" Width="170" Margin="5,0,0,0" />
+            <TextBlock Text="Price" Width="100" />
+            <TextBlock Text="Previous" Width="100" />
+            <TextBlock Text="Change" Width="105" />
+            <TextBlock Text="Time" Width="105" />
+        </StackPanel>
+        <ListBox x:Name="lbStockPrices" 
+             ItemsSource="{Binding Path=DisplayStockPrices}" 
+             BorderThickness="0" FontFamily="Segoe UI"
+             Grid.Row="2">
+            <ListBox.ItemTemplate>
+                <DataTemplate>
+                    <StackPanel Orientation="Horizontal" Height="25">
+                        <TextBlock Text="{Binding CompanyName}" Width="125" FontSize="15" Margin="10,0,0,0"/>
+                        <TextBlock Text="{Binding Symbol}" Width="45" FontSize="15" Margin="10,0,0,0"/>
+                        <TextBlock Text="{Binding CurrentPrice}" Width="100" FontSize="15" />
+                        <TextBlock Text="{Binding PreviousPrice}" Width="100" FontSize="15" />
+                        <Image Source="{Binding Delta, Converter={StaticResource DeltaToIconConverter}}" Width="20" />
+                        <TextBlock Text="{Binding Delta, Converter={StaticResource AbsoluteNumberConverter}}" Width="85" FontSize="15" />
+                        <!--<TextBlock Text="{Binding Timestamp, Converter={StaticResource DateTimeToTimeConverter}}" Width="100" FontSize="15" />-->
+                    </StackPanel>
+                </DataTemplate>
+            </ListBox.ItemTemplate>
+        </ListBox>
+    </Grid>
+ </UserControl>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/StocksView.xaml.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace MetroWpf.Presentation.Stocks
+{
+    /// <summary>
+    /// Interaction logic for StocksView.xaml
+    /// </summary>
+    public partial class StocksView : UserControl
+    {
+        public StocksView()
+        {
+            InitializeComponent();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/MetroWpf/Presentation/Stocks/StocksViewModel.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,107 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Windows.Input;
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.Command;
+using Stocks.Common;
+using Stocks.Common.Events;
+
+namespace MetroWpf.Presentation.Stocks
+{
+    public class StocksViewModel : ViewModelBase
+    {
+        private readonly IStocksService _service;
+
+        public BindingList<DisplayStockPrice> DisplayStockPrices { get; set; }
+        public ICommand ServiceCommand { get; set; }
+        public ICommand SubscriptionCommand { get; set; }
+
+        public StocksViewModel(IStocksService service)
+        {
+            _service = service;
+            GetLatestPrices();
+
+            SubscriptionCommand = new RelayCommand(SubscriptionCommandExecute);
+            ServiceCommand = new RelayCommand(ServiceRunningCommandExecute);
+
+            var priceUpdates = Observable.FromEventPattern<PriceChangedEventArgs>(
+                _service, "PriceChanged");
+
+            priceUpdates.Where(e => Subscribed)
+                //.Throttle(TimeSpan.FromSeconds(1))
+                .Subscribe(PriceChanged);
+        }
+
+        public void PriceChanged(EventPattern<PriceChangedEventArgs> e)
+        {
+            var displayRate = DisplayStockPrices.First(
+                rate => rate.Symbol == e.EventArgs.Price.Symbol);
+
+            if (displayRate != null)
+                displayRate.Update(e.EventArgs.Price);
+        }
+
+
+        private void GetLatestPrices()
+        {
+            DisplayStockPrices = new BindingList<DisplayStockPrice>();
+            var currentRates = _service.GetFullCurrentPrices();
+            foreach (var latestRate in currentRates)
+            {
+                var displayRate = DisplayStockPrice.Create(latestRate);
+                DisplayStockPrices.Add(displayRate);
+            }
+        }
+
+        private const string SubscribedPropertyName = "Subscribed";
+        private bool _subscribed = false;
+
+        public bool Subscribed
+        {
+            get { return _subscribed; }
+            set
+            {
+                if (_subscribed == value) return;
+                _subscribed = value;
+                RaisePropertyChanged(SubscribedPropertyName);
+            }
+        }
+
+        private const string ServiceRunningPropertyName = "ServiceRunning";
+        private bool _serviceRunning;
+
+        public bool ServiceRunning
+        {
+            get { return _serviceRunning; }
+            set
+            {
+                if (_serviceRunning == value) return;
+                _serviceRunning = value;
+                RaisePropertyChanged(ServiceRunningPropertyName);
+            }
+        }
+
+        private void ServiceRunningCommandExecute()
+        {
+            if (_service.IsRunning)
+            {
+                _service.Stop();
+                ServiceRunning = false;
+            }
+            else
+            {
+                _service.Start();
+                ServiceRunning = true;
+            }
+        }
+
+        private void SubscriptionCommandExecute()
+        {
+            //toggle subscribed
+            Subscribed = !Subscribed;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/ConfigurationService.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using Stocks.Common;
+using Stocks.Common.Core;
+using Stocks.Common.Models;
+using Newtonsoft.Json;
+
+namespace Stocks.Common
+{
+  public class ConfigurationService : IConfigurationService
+  {
+    private string jsonFilename;
+    private string serviceUrlPrefix = "http://finance.yahoo.com/d/quotes.csv?s=";
+    private string serviceUrlSuffix = "&f=snl1";
+
+    public ConfigurationService(string filename)
+    {
+      jsonFilename = filename;
+    }
+    public List<Company> GetCompanies()
+    {
+      return new FileSerializer().DeserializeJson<Company>(jsonFilename);
+    }
+
+    public string GetServiceUrl(string symbolCsv)
+    {
+      if (string.IsNullOrEmpty(symbolCsv))
+        throw new ArgumentException();
+
+      return string.Concat(serviceUrlPrefix, symbolCsv, serviceUrlSuffix);
+    }
+
+    public string GetServiceUrl(string[] symbols)
+    {
+      if (symbols == null || symbols.Length == 0)
+        throw new ArgumentException();
+      
+      var symbolCsv = string.Join(",", symbols);
+      return GetServiceUrl(symbolCsv);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Core/ExtensionMethods.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,18 @@
+using System;
+
+namespace Stocks.Common.Core
+{
+  public static class StringHelper
+  {
+    /// <summary>
+    /// Receives string and returns the string with its letters reversed.
+    /// </summary>
+    public static string Reverse(this string s)
+    {
+      if (s == null) return null;
+      char[] arr = s.ToCharArray();
+      Array.Reverse(arr);
+      return new string(arr);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Core/FileSerializer.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Stocks.Common.Core
+{
+  public class FileSerializer
+  {
+    public void SerializeJson(string filename, object obj)
+    {
+      string json = JsonConvert.SerializeObject(obj);
+      Serialize(filename, json);
+    }
+
+    public void Serialize(string filename, string text)
+    {
+      using (StreamWriter writer = new StreamWriter(filename))
+        { writer.Write(text); }
+    }
+
+    public void Serialize(string filename, IFormatter formatter, object objectToSerialize)
+    {
+      using (Stream stream = File.Open(filename, FileMode.Create))
+        formatter.Serialize(stream, objectToSerialize);
+    }
+
+    public string Deserialize(string filename)
+    { 
+      StringBuilder sb = new StringBuilder();
+      using (StreamReader reader = new StreamReader(filename))
+        if (reader != null)
+          sb.AppendLine(reader.ReadToEnd());
+
+      return sb.ToString();       
+    }
+
+    public List<T> DeserializeJson<T>(string filename)
+    {
+      var json = Deserialize(filename);
+      return JsonConvert.DeserializeObject<List<T>>(json);
+    }
+
+    public T[] Deserialize<T>(string filename, IFormatter formatter, Type type)
+    {
+      using (Stream stream = File.Open(filename, FileMode.Open))
+      {
+        var items = (T[])formatter.Deserialize(stream);
+        return items;
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Core/TimedDelegates.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,20 @@
+using System;
+using System.Diagnostics;
+
+namespace Stocks.Common.Core
+{
+  public class TimedDelegates
+  {
+    public static T Execute<T>(
+      Func<T, T> func,
+      T paramIn,
+      out Stopwatch stopwatch)
+    {
+      stopwatch = new Stopwatch();
+      stopwatch.Start();
+      T result = func(paramIn);
+      stopwatch.Stop();
+      return result;
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Events/PriceChangedEventArgs.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,10 @@
+using System;
+using Stocks.Common.Models;
+
+namespace Stocks.Common.Events
+{
+  public class PriceChangedEventArgs : EventArgs
+  {
+    public Price Price { get; set; }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Exceptions/InvalidWebPriceData.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Stocks.Common.Exceptions
+{
+  [Serializable]
+  public class InvalidWebPriceDataException : Exception
+  {
+    public string WebPriceData { get; set; }
+    public InvalidWebPriceDataException() : base ()
+    {
+
+    }
+    public InvalidWebPriceDataException(string webPriceData) : base(webPriceData)
+    {
+      WebPriceData = webPriceData;
+    }
+
+    public InvalidWebPriceDataException(string webPriceData, Exception innerException)
+      : base("Unexpected web price data", innerException)
+    {
+      WebPriceData = webPriceData;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Factory.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,36 @@
+using NLog;
+using Stocks.Common.Core;
+using Stocks.Common.Models;
+using System;
+using Stocks.Common.Exceptions;
+
+namespace Stocks.Common
+{
+  public class Factory
+  {
+    public static Price CreatePrice(string webPriceData)
+    {
+      if (string.IsNullOrEmpty(webPriceData))
+        throw new InvalidWebPriceDataException(webPriceData);
+
+      try
+      {
+        var symbol = webPriceData.Substring(1, webPriceData.IndexOf('"', 2) - 1);
+
+        decimal price = decimal.Parse(webPriceData.Substring(
+            webPriceData.Length - webPriceData.Reverse().IndexOf(",")));
+
+        return new Price()
+        {
+          Symbol = symbol,
+          PreviousPrice = price,
+          CurrentPrice = price
+        };
+      }
+      catch (Exception e)
+      {
+        throw new InvalidWebPriceDataException(webPriceData, e);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Fakes/FakeWebClientShim.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,23 @@
+
+namespace Stocks.Common.Fakes
+{
+  public class FakeWebClientShim : IWebClientShim
+  {
+    private string _downloadString;
+
+    public FakeWebClientShim(string downloadString = "")
+    {
+      _downloadString = downloadString;
+    }
+
+    public string DownloadString(string address)
+    {
+      return _downloadString;
+    }
+
+    public void Dispose()
+    {
+      // do nothing
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/IConfigurationService.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using Stocks.Common.Models;
+
+namespace Stocks.Common
+{
+  public interface IConfigurationService
+  {
+    List<Company> GetCompanies();
+    string GetServiceUrl(string symbolCsv);
+    string GetServiceUrl(string[] symbols);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/IStocksService.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using Stocks.Common.Models;
+
+namespace Stocks.Common
+{
+  public interface IStocksService
+  {
+    IList<Price> GetFullCurrentPrices();
+    bool IsRunning { get; }
+    void Start();
+    void Stop();
+  }
+}
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/IWebClientShim.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,8 @@
+using System;
+namespace Stocks.Common
+{
+  public interface IWebClientShim : IDisposable
+  {
+    string DownloadString(string address);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Models/Company.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,9 @@
+
+namespace Stocks.Common.Models
+{
+  public class Company
+  {
+    public string Symbol { get; set; }
+    public string Name { get; set; }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Models/Price.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,129 @@
+using Stocks.Common.Core;
+using System.Collections;
+using System;
+using System.Collections.Generic;
+
+namespace Stocks.Common.Models
+{
+  public class Price : IEquatable<Price>, IComparable<Price>, IComparable
+  {
+    public string Symbol { get; set; }
+    public decimal CurrentPrice { get; set; }
+    public decimal PreviousPrice { get; set; }
+
+    public Price()
+    {
+    }
+
+    public Price(string symbol, decimal currentPrice, decimal previousPrice)
+      : this()
+    {
+      Symbol = symbol;
+      CurrentPrice = currentPrice;
+      PreviousPrice = previousPrice;
+    }
+
+    public override bool Equals(object obj)
+    {
+      if (obj is Price)
+        return Equals(obj as Price);
+      else
+        return false;
+    }
+
+    public bool Equals(Price other)
+    {
+      return (Symbol == other.Symbol
+        && CurrentPrice == other.CurrentPrice
+        && PreviousPrice == other.PreviousPrice);
+    }
+
+    public int CompareTo(Price other)
+    {
+      return Symbol.CompareTo(other.Symbol);
+    }
+
+    public int CompareTo(Price other, PriceComparisonType comparisonType)
+    {
+      switch (comparisonType)
+      {
+        case PriceComparisonType.NotSet:
+        case PriceComparisonType.Symbol:
+          return Symbol.CompareTo(other.Symbol);
+        case PriceComparisonType.CurrentPrice:
+          return CurrentPrice.CompareTo(other.CurrentPrice);
+        case PriceComparisonType.PreviousPrice:
+          return PreviousPrice.CompareTo(other.PreviousPrice);
+        default:
+          throw new Exception("Unknown comparison type");
+      }
+    }
+
+    public int CompareTo(object obj)
+    {
+      Price other;
+      if (obj is Price)
+        other = obj as Price;
+      else
+        throw new ArgumentException("obj is not a Price");
+
+      return CompareTo(other);
+    }
+    public override int GetHashCode()
+    {
+      int hash = 13;
+      hash = (hash * 7) + Symbol.GetHashCode();
+      hash = (hash * 7) + CurrentPrice.GetHashCode();
+      hash = (hash * 7) + PreviousPrice.GetHashCode();
+      return hash;
+    }
+
+    public static bool operator ==(Price lhs, Price rhs)
+    {
+      if (System.Object.ReferenceEquals(lhs, rhs))
+        return true;
+
+      if (((object)lhs == null) || ((object)rhs == null))
+        return false;
+
+      return lhs.Symbol == rhs.Symbol
+        && lhs.CurrentPrice == rhs.CurrentPrice
+        && lhs.PreviousPrice == rhs.PreviousPrice;
+    }
+
+    public static bool operator !=(Price lhs, Price rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+
+    public class PriceComparer : IComparer<Price>, IComparer
+    {
+      public PriceComparisonType ComparisonMethod { get; set; }
+
+      public int Compare(Price x, Price y)
+      {
+        return x.CompareTo(y, ComparisonMethod);
+      }
+
+      public int Compare(object x, object y)
+      {
+        Price lhs, rhs;
+
+        if (x is Price)
+          lhs = x as Price;
+        else
+          throw new ArgumentException("x is not a Price");
+
+        if (y is Price)
+          rhs = y as Price;
+        else
+          throw new ArgumentException("y is not a Price");
+
+        return lhs.CompareTo(rhs, ComparisonMethod);
+      }
+    }
+  }
+
+  public enum PriceComparisonType { NotSet = 0, Symbol, CurrentPrice, PreviousPrice }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Models/Quote.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,10 @@
+
+namespace Stocks.Common.Models
+{
+  public class Quote
+  {
+    public string Symbol { get; set; }
+    public string Name { get; set; }
+    public double LastTrade { get; set; }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Models/SummaryStats.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,35 @@
+using System;
+using System.Text;
+
+namespace Stocks.Common.Models
+{
+  public class SummaryStats
+  {
+    public WebRequestStats LastWebRequest { get; set; }
+    public int PriceChangeEvents { get; set; }
+    public int NumberOfRequests { get; set; }
+    public DateTime TimeServiceStarted { get; set; }
+
+    public void Reset()
+    {
+      LastWebRequest = new WebRequestStats();
+      PriceChangeEvents = 0;
+      NumberOfRequests = 0;
+      TimeServiceStarted = DateTime.Now;
+    }
+
+    public override string ToString()
+    {
+      var sb = new StringBuilder();
+      sb.AppendLine("Stocks Service Summary Stats:");
+      sb.AppendLine(string.Format("  Time service started: {0}", TimeServiceStarted));
+      sb.AppendLine(string.Format("  Number of requests: {0}", NumberOfRequests));
+      sb.AppendLine(string.Format("  Number of price change events: {0}", PriceChangeEvents));
+      sb.AppendLine(string.Format("  Number of symbols sent on last request: {0}", LastWebRequest.SymbolCount));
+      sb.AppendLine(string.Format("  Number of prices in last response: {0}", LastWebRequest.PricesDownloaded));
+      sb.AppendLine(string.Format("  Time taken for last request: {0}", LastWebRequest.Duration));
+      //sb.AppendLine(string.Format("  Response string for last request: {0}", LastWebRequest.Response));
+      return sb.ToString();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Models/WebRequestStats.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,11 @@
+namespace Stocks.Common.Models
+{
+  public class WebRequestStats
+  {
+    public int Duration { get; set; }
+    public int PricesDownloaded { get; set; }
+    public string Response { get; set; }
+    public string Request { get; set; }
+    public int SymbolCount { get; set; }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Properties/AssemblyInfo.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Stocks.Common")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Stocks.Common")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("474b578e-a3b7-49d6-921d-f9c07c16ed92")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/Stocks.Common.csproj	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{847365D2-E27B-44C3-8DF4-B749D9FA65D7}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Stocks.Common</RootNamespace>
+    <AssemblyName>Stocks.Common</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\Libs\Newtonsoft.Json.4.0.8\lib\net40\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NLog">
+      <HintPath>..\Libs\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ConfigurationService.cs" />
+    <Compile Include="Core\ExtensionMethods.cs" />
+    <Compile Include="Core\FileSerializer.cs" />
+    <Compile Include="Core\TimedDelegates.cs" />
+    <Compile Include="Events\PriceChangedEventArgs.cs" />
+    <Compile Include="Exceptions\InvalidWebPriceData.cs" />
+    <Compile Include="Factory.cs" />
+    <Compile Include="Fakes\FakeWebClientShim.cs" />
+    <Compile Include="IConfigurationService.cs" />
+    <Compile Include="IStocksService.cs" />
+    <Compile Include="IWebClientShim.cs" />
+    <Compile Include="Models\Company.cs" />
+    <Compile Include="Models\Price.cs" />
+    <Compile Include="Models\Quote.cs" />
+    <Compile Include="Models\SummaryStats.cs" />
+    <Compile Include="Models\WebRequestStats.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="WebClientShim.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Common/WebClientShim.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,28 @@
+using System.Net;
+using System;
+
+namespace Stocks.Common
+{
+  // Shim to wrap WebClient component to allow the shim to 
+  // be mocked or stubbed for unit tests.
+  // Favours injection and composition over inheritence
+  public class WebClientShim : IWebClientShim
+  {
+    private WebClient _webClient;
+
+    public WebClientShim(WebClient webClient)
+    {
+      _webClient = webClient;
+    }
+
+    public string DownloadString(string address)
+    {
+      return _webClient.DownloadString(address).ToString();
+    }
+
+    public void Dispose()
+    {
+      _webClient.Dispose();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Service/AssemblyInit.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,23 @@
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using NLog;
+
+namespace Stocks.Service
+{
+    internal class AssemblyInit
+    {
+        private static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
+        public AssemblyInit()
+        {
+            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(
+                Assembly.GetExecutingAssembly().Location);
+
+            logger.Info("Init: {0} {1} ",
+                        Assembly.GetExecutingAssembly().GetName(),
+                        fvi.ProductVersion);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Service/Properties/AssemblyInfo.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Stocks.Service")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Stocks.Service")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e6a7b2c2-b543-498c-ad46-b33cc27b57fd")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Service/Stocks.Service.csproj	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{47F54122-5381-48D8-ACF7-72BBE0353511}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Stocks.Service</RootNamespace>
+    <AssemblyName>Stocks.Service</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="NLog">
+      <HintPath>..\Libs\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AssemblyInit.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="StocksService.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Stocks.Common\Stocks.Common.csproj">
+      <Project>{847365D2-E27B-44C3-8DF4-B749D9FA65D7}</Project>
+      <Name>Stocks.Common</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.Service/StocksService.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using NLog;
+using Stocks.Common;
+using Stocks.Common.Core;
+using Stocks.Common.Events;
+using Stocks.Common.Models;
+
+namespace Stocks.Service
+{
+    public class StocksService : IStocksService
+    {
+        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
+
+        private IList<Company> _companies;
+        private readonly IConfigurationService _configurationService;
+        private List<Price> _currentPrices;
+        private string _serviceUrl;
+        private readonly IWebClientShim _webClient;
+
+        public bool IsRunning { get; private set; }
+        public SummaryStats Stats { get; private set; }
+
+        public StocksService(
+          IConfigurationService configurationService,
+          IWebClientShim webClientShim)
+        {
+            new AssemblyInit();
+
+            _webClient = webClientShim;
+            _configurationService = configurationService;
+            Stats = new SummaryStats();
+
+            GetCompanyList();
+        }
+
+        private void GetCompanyList()
+        {
+            _companies = _configurationService.GetCompanies();
+
+            var symbolsCsv = _companies.Select(
+              c => c.Symbol).Aggregate((c, d) => c + "," + d);
+
+            _serviceUrl = _configurationService.GetServiceUrl(symbolsCsv);
+        }
+
+        public IList<Price> GetFullCurrentPrices()
+        {
+            return _companies.Select(company => new Price(company.Symbol, 0, 0)).ToList();
+        }
+
+        public event PriceChangedEventHandler PriceChanged;
+        public delegate void PriceChangedEventHandler(object sender, PriceChangedEventArgs e);
+        protected virtual void OnPriceChanged(Price price)
+        {
+            Stats.PriceChangeEvents++;
+
+            if (PriceChanged != null)
+                PriceChanged(this, new PriceChangedEventArgs() { Price = price });
+        }
+
+        public void Start()
+        {
+            PrepareForServiceStarting();
+            Task.Factory.StartNew(DownloadPrices);
+        }
+
+        public void Stop()
+        {
+            IsRunning = false;
+            Log.Debug("StockService stopped");
+        }
+
+        private void PrepareForServiceStarting()
+        {
+            Log.Debug("StockService starting");
+            IsRunning = true;
+            Stats.Reset();
+            _currentPrices = new List<Price>(_companies.Count);
+        }
+
+        private void DownloadPrices()
+        {
+            try
+            {
+                while (IsRunning)
+                {
+                    Stopwatch timeToDownload;
+                    var webResponse = TimedDelegates.Execute(
+                      _webClient.DownloadString,
+                      _serviceUrl,
+                      out timeToDownload);
+
+                    PopulatePricesFromWebResponse(webResponse);
+                    UpdateStats(timeToDownload, webResponse);
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error("Exception during DownloadPrices()");
+                Log.Error("Stack Trace {0}: /r/nException Message: {1}", e.StackTrace, e.Message);
+                this.Stop();
+            }
+        }
+
+        private void PopulatePricesFromWebResponse(string webResponse)
+        {
+            var webPrices = webResponse.Split(
+              new[] { "\n", "\r\n" },
+              StringSplitOptions.RemoveEmptyEntries);
+
+            foreach (var webPriceData in webPrices)
+            {
+                var webPrice = Factory.CreatePrice(webPriceData);
+                var localPrice = _currentPrices.Find(x => x.Symbol == webPrice.Symbol);
+
+                if (localPrice == null)
+                {
+                    _currentPrices.Add(new Price(webPrice.Symbol, webPrice.CurrentPrice, webPrice.PreviousPrice));
+                    continue;
+                }
+
+                if (!localPrice.Equals(webPrice))
+                    UpdateLocalPrice(webPrice, localPrice);
+            }
+        }
+
+        private void UpdateLocalPrice(Price webPrice, Price localPrice)
+        {
+            localPrice.PreviousPrice = localPrice.CurrentPrice;
+            localPrice.CurrentPrice = webPrice.CurrentPrice;
+            OnPriceChanged(localPrice);
+        }
+
+        private void UpdateStats(Stopwatch timeToDownload, string webResponse)
+        {
+            Stats.LastWebRequest.Duration = (int)timeToDownload.ElapsedMilliseconds;
+            Stats.LastWebRequest.PricesDownloaded = _currentPrices.Count;
+            Stats.LastWebRequest.Response = webResponse;
+            Stats.LastWebRequest.Request = _serviceUrl;
+            Stats.LastWebRequest.SymbolCount = _companies.Count;
+            Stats.NumberOfRequests++;
+            Log.Trace(Stats);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/App.xaml	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,15 @@
+<Application x:Class="Stocks.UI.App"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:local="clr-namespace:Stocks.UI" 
+             mc:Ignorable="d">
+    <Application.Resources>
+        <ResourceDictionary>
+            <!--Global IoC Locator-->
+            <local:Locator x:Key="Locator"
+                         d:IsDataSource="True" />
+        </ResourceDictionary>
+    </Application.Resources>
+</Application>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/App.xaml.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Windows;
+
+namespace Stocks.UI
+{
+    /// <summary>
+    /// Interaction logic for App.xaml
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Converters/AbsoluteNumberConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace Stocks.UI.Converters
+{
+  public class AbsoluteNumberConverter : IValueConverter
+  {
+    #region IValueConverter Members
+
+    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+      return Math.Abs((decimal) value);
+    }
+
+    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+      throw new NotImplementedException();
+    }
+
+    #endregion
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Converters/BoolToServiceRunningTextConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace Stocks.UI.Converters
+{
+    public class BoolToServiceRunningTextConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return (bool) value ? "Service Running" : "Service Stopped";
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Converters/BoolToSubscribedTextConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,22 @@
+using System;
+using System.Windows.Data;
+
+namespace Stocks.UI.Converters
+{
+    public class BoolToSubscribedTextConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return (bool) value ? "Subscribed" : "Unsubscribed";
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Converters/DateTimeToTimeConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,24 @@
+using System;
+using System.Windows.Data;
+
+namespace Stocks.UI.Converters
+{
+    public class DateTimeToTimeConverter : IValueConverter
+    {
+        #region IValueConverter Members
+
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            string dateTimeString = ((DateTime) value).ToString("HH:mm:ss.ffff");
+
+            return dateTimeString;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Converters/DeltaToIconConverter.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,46 @@
+using System;
+using System.Windows.Data;
+using System.Windows.Media.Imaging;
+
+namespace Stocks.UI.Converters
+{
+		public class DeltaToIconConverter : IValueConverter
+		{
+		#region IValueConverter Members
+
+		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			string uri;
+			BitmapImage image;
+			decimal delta;
+			string file = "UNK";
+			
+			try
+			{
+        delta = (decimal) value;
+        {
+          if (delta > 0)
+            file = "UP";
+          else if (delta < 0)
+            file = "DOWN";
+          else
+            file = "LEVEL";
+        }
+			}
+			finally
+			{
+				uri = string.Format("../Images/{0}.png", file);
+				image = new BitmapImage(new Uri(uri, UriKind.Relative));
+			}
+
+			return image;
+		}
+
+		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			throw new NotImplementedException();
+		}
+
+		#endregion
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/DisplayStockPrice.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,90 @@
+using GalaSoft.MvvmLight;
+using Stocks.Common.Models;
+
+namespace Stocks.UI
+{
+    public class DisplayStockPrice : ObservableObject
+    {
+        public static DisplayStockPrice Create(Price price)
+        {
+            return new DisplayStockPrice()
+                       {
+                           Symbol = price.Symbol,
+                           CurrentPrice = price.CurrentPrice,
+                           PreviousPrice = price.PreviousPrice
+                       };
+        }
+
+        public void Update(Price price)
+        {
+            Symbol = price.Symbol;
+            CurrentPrice = price.CurrentPrice;
+            PreviousPrice = price.PreviousPrice;
+        }
+
+        public const string SymbolPropertyName = "Symbol";
+        private string _symbol;
+        public string Symbol
+        {
+            get { return _symbol; }
+            private set
+            {
+                if (_symbol == value) return;
+                _symbol = value;
+                RaisePropertyChanged(SymbolPropertyName);
+            }
+        }
+
+        public const string CompanyNamePropertyName = "CompanyName";
+        private string _companyName;
+        public string CompanyName
+        {
+            get { return _companyName; }
+            private set
+            {
+                if (_companyName == value) return;
+                _companyName = value;
+                RaisePropertyChanged(CompanyNamePropertyName);
+            }
+        }
+
+        public const string CurrentPricePropertyName = "CurrentPrice";
+        private decimal _currentPrice = 0;
+        public decimal CurrentPrice
+        {
+            get { return _currentPrice; }
+            private set
+            {
+                if (_currentPrice == value) return;
+                _currentPrice = value;
+                RaisePropertyChanged(CurrentPricePropertyName);
+            }
+        }
+
+        public const string PreviousPricePropertyName = "PreviousPrice";
+        private decimal _previousPrice = 0;
+        public decimal PreviousPrice
+        {
+            get { return _previousPrice; }
+            private set
+            {
+                if (_previousPrice == value) return;
+                _previousPrice = value;
+                RaisePropertyChanged(PreviousPricePropertyName);
+            }
+        }
+
+        public const string DeltaPropertyName = "Delta";
+        private decimal _delta = 0;
+        public decimal Delta
+        {
+            get { return _delta; }
+            private set
+            {
+                if (_delta == value) return;
+                _delta = value;
+                RaisePropertyChanged(DeltaPropertyName);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Locator.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,12 @@
+using GalaSoft.MvvmLight.Ioc;
+
+namespace Stocks.UI
+{
+    public class Locator
+    {
+        public StocksViewModel StocksViewModel
+        {
+            get { return SimpleIoc.Default.GetInstance<StocksViewModel>(); }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Properties/AssemblyInfo.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Stocks.UI")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Stocks.UI")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set 
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>.  For example, if you are using US english
+//in your source files, set the <UICulture> to en-US.  Then uncomment
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+    //(used if a resource is not found in the page, 
+    // or application resource dictionaries)
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+    //(used if a resource is not found in the page, 
+    // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Properties/Resources.Designer.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.261
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Stocks.UI.Properties
+{
+
+
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Stocks.UI.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Properties/Resources.resx	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Properties/Settings.Designer.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.261
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Stocks.UI.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Properties/Settings.settings	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/Stocks.UI.csproj	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{63E512BA-D038-4672-9C02-85DD49744E0F}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Stocks.UI</RootNamespace>
+    <AssemblyName>Stocks.UI</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="GalaSoft.MvvmLight.Extras.WPF4">
+      <HintPath>..\Libs\MvvmLight.Extras.4.0.0\GalaSoft.MvvmLight.Extras.WPF4.dll</HintPath>
+    </Reference>
+    <Reference Include="GalaSoft.MvvmLight.WPF4">
+      <HintPath>..\Libs\MvvmLight.4.0.0\GalaSoft.MvvmLight.WPF4.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Practices.ServiceLocation">
+      <HintPath>..\Libs\MvvmLight.Extras.4.0.0\Microsoft.Practices.ServiceLocation.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Reactive">
+      <HintPath>..\Libs\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Interactivity">
+      <HintPath>..\Libs\System.Windows.Interactivity\System.Windows.Interactivity.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+  </ItemGroup>
+  <ItemGroup>
+    <ApplicationDefinition Include="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </ApplicationDefinition>
+    <Compile Include="Converters\AbsoluteNumberConverter.cs" />
+    <Compile Include="Converters\BoolToServiceRunningTextConverter.cs" />
+    <Compile Include="Converters\BoolToSubscribedTextConverter.cs" />
+    <Compile Include="Converters\DateTimeToTimeConverter.cs" />
+    <Compile Include="Converters\DeltaToIconConverter.cs" />
+    <Compile Include="DisplayStockPrice.cs" />
+    <Compile Include="Locator.cs" />
+    <Compile Include="StocksViewModel.cs" />
+    <Page Include="StocksView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Compile Include="App.xaml.cs">
+      <DependentUpon>App.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="StocksView.xaml.cs">
+      <DependentUpon>StocksView.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <AppDesigner Include="Properties\" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Stocks.Common\Stocks.Common.csproj">
+      <Project>{847365D2-E27B-44C3-8DF4-B749D9FA65D7}</Project>
+      <Name>Stocks.Common</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/StocksView.xaml	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,69 @@
+<UserControl x:Class="Stocks.UI.StocksView"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:Converters="clr-namespace:Stocks.UI.Converters" 
+             mc:Ignorable="d" 
+             d:DesignHeight="100" d:DesignWidth="600"
+             d:DataContext="{Binding StocksViewModel, Source={StaticResource Locator}}">
+
+    <Grid x:Name="LayoutRoot">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="60" />
+            <RowDefinition Height="20" />
+            <RowDefinition Height="280" />
+            <RowDefinition Height="180" />
+        </Grid.RowDefinitions>
+        <Grid.Resources>
+            <Converters:BoolToServiceRunningTextConverter x:Key="BoolToServiceRunningTextConverter" />
+            <Converters:BoolToSubscribedTextConverter x:Key="BoolToSubscribedTextConverter" />
+            <Converters:DeltaToIconConverter x:Key="DeltaToIconConverter" />
+            <Converters:AbsoluteNumberConverter x:Key="AbsoluteNumberConverter" />
+            <!--<Converters:DateTimeToTimeConverter x:Key="DateTimeToTimeConverter" />-->
+        </Grid.Resources>
+
+        <StackPanel Grid.Row="0" Orientation="Horizontal">
+            <Button x:Name="btnServiceRunning"
+              Width="100"
+              Height="30"
+              HorizontalAlignment="Left" 
+              Content="{Binding Path=ServiceRunning, Converter={StaticResource BoolToServiceRunningTextConverter}}" 
+              Command="{Binding Path=ServiceCommand, Mode=TwoWay}"
+              Margin="5,0,0,0"/>
+            <Button x:Name="btnSubscribe"
+              Width="100"
+              Height="30"
+              Margin="10,0,0,0"
+              HorizontalAlignment="Left" 
+              Content="{Binding Path=Subscribed, Converter={StaticResource BoolToSubscribedTextConverter}}" 
+              Command="{Binding Path=SubscriptionCommand, Mode=TwoWay}" />
+        </StackPanel>
+
+        <StackPanel Grid.Row="1" Orientation="Horizontal">
+            <TextBlock Text="Company" Width="170" Margin="5,0,0,0" />
+            <TextBlock Text="Price" Width="100" />
+            <TextBlock Text="Previous" Width="100" />
+            <TextBlock Text="Change" Width="105" />
+            <TextBlock Text="Time" Width="105" />
+        </StackPanel>
+        <ListBox x:Name="lbStockPrices" 
+             ItemsSource="{Binding Path=DisplayStockPrices}" 
+             BorderThickness="0" FontFamily="Segoe UI"
+             Grid.Row="2">
+            <ListBox.ItemTemplate>
+                <DataTemplate>
+                    <StackPanel Orientation="Horizontal" Height="25">
+                        <TextBlock Text="{Binding CompanyName}" Width="125" FontSize="15" Margin="10,0,0,0"/>
+                        <TextBlock Text="{Binding Symbol}" Width="45" FontSize="15" Margin="10,0,0,0"/>
+                        <TextBlock Text="{Binding CurrentPrice}" Width="100" FontSize="15" />
+                        <TextBlock Text="{Binding PreviousPrice}" Width="100" FontSize="15" />
+                        <Image Source="{Binding Delta, Converter={StaticResource DeltaToIconConverter}}" Width="20" />
+                        <TextBlock Text="{Binding Delta, Converter={StaticResource AbsoluteNumberConverter}}" Width="85" FontSize="15" />
+                        <!--<TextBlock Text="{Binding Timestamp, Converter={StaticResource DateTimeToTimeConverter}}" Width="100" FontSize="15" />-->
+                    </StackPanel>
+                </DataTemplate>
+            </ListBox.ItemTemplate>
+        </ListBox>
+    </Grid>
+    </UserControl>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/StocksView.xaml.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace Stocks.UI
+{
+    /// <summary>
+    /// Interaction logic for StocksView.xaml
+    /// </summary>
+    public partial class StocksView : UserControl
+    {
+        public StocksView()
+        {
+            InitializeComponent();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MetroWpf/Stocks.UI/StocksViewModel.cs	Tue Mar 20 13:37:46 2012 +0000
@@ -0,0 +1,107 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Windows.Input;
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.Command;
+using Stocks.Common;
+using Stocks.Common.Events;
+
+namespace Stocks.UI
+{
+    public class StocksViewModel : ViewModelBase
+    {
+        private readonly IStocksService _service;
+
+        public BindingList<DisplayStockPrice> DisplayStockPrices { get; set; }
+        public ICommand ServiceCommand { get; set; }
+        public ICommand SubscriptionCommand { get; set; }
+
+        public StocksViewModel(IStocksService service)
+        {
+            _service = service;
+            GetLatestPrices();
+
+            SubscriptionCommand = new RelayCommand(SubscriptionCommandExecute);
+            ServiceCommand = new RelayCommand(ServiceRunningCommandExecute);
+
+            var priceUpdates = Observable.FromEventPattern<PriceChangedEventArgs>(
+                _service, "PriceChanged");
+
+            priceUpdates.Where(e => Subscribed)
+                //.Throttle(TimeSpan.FromSeconds(1))
+                .Subscribe(PriceChanged);
+        }
+
+        public void PriceChanged(EventPattern<PriceChangedEventArgs> e)
+        {
+            var displayRate = DisplayStockPrices.First(
+                rate => rate.Symbol == e.EventArgs.Price.Symbol);
+
+            if (displayRate != null)
+                displayRate.Update(e.EventArgs.Price);
+        }
+
+
+        private void GetLatestPrices()
+        {
+            DisplayStockPrices = new BindingList<DisplayStockPrice>();
+            var currentRates = _service.GetFullCurrentPrices();
+            foreach (var latestRate in currentRates)
+            {
+                var displayRate = DisplayStockPrice.Create(latestRate);
+                DisplayStockPrices.Add(displayRate);
+            }
+        }
+
+        private const string SubscribedPropertyName = "Subscribed";
+        private bool _subscribed = false;
+
+        public bool Subscribed
+        {
+            get { return _subscribed; }
+            set
+            {
+                if (_subscribed == value) return;
+                _subscribed = value;
+                RaisePropertyChanged(SubscribedPropertyName);
+            }
+        }
+
+        private const string ServiceRunningPropertyName = "ServiceRunning";
+        private bool _serviceRunning;
+
+        public bool ServiceRunning
+        {
+            get { return _serviceRunning; }
+            set
+            {
+                if (_serviceRunning == value) return;
+                _serviceRunning = value;
+                RaisePropertyChanged(ServiceRunningPropertyName);
+            }
+        }
+
+        private void ServiceRunningCommandExecute()
+        {
+            if (_service.IsRunning)
+            {
+                _service.Stop();
+                ServiceRunning = false;
+            }
+            else
+            {
+                _service.Start();
+                ServiceRunning = true;
+            }
+        }
+
+        private void SubscriptionCommandExecute()
+        {
+            //toggle subscribed
+            Subscribed = !Subscribed;
+        }
+    }
+}
\ No newline at end of file
--- a/MetroWpf/packages/repositories.config	Thu Mar 15 06:59:15 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<repositories>
-  <repository path="..\MetroWpf\packages.config" />
-</repositories>
\ No newline at end of file