diff --git a/RateMyApp/Controls/FeedbackOverlay.xaml.cs b/RateMyApp/Controls/FeedbackOverlay.xaml.cs
index 9c70353..1075ff3 100644
--- a/RateMyApp/Controls/FeedbackOverlay.xaml.cs
+++ b/RateMyApp/Controls/FeedbackOverlay.xaml.cs
@@ -12,18 +12,31 @@
using System.Linq;
using System.Xml;
using System.Xml.Linq;
-using Microsoft.Phone.Controls;
-using Microsoft.Phone.Info;
-using Microsoft.Phone.Tasks;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Threading;
using System.Windows;
+using RateMyApp.Helpers;
+
+#if SILVERLIGHT
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Info;
+using Microsoft.Phone.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
+using Visibility = System.Windows.Visibility;
+#else
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Media;
+using Windows.ApplicationModel.Email;
+using System.IO;
+using Windows.Storage;
+using Windows.Security.ExchangeActiveSyncProvisioning;
+using Windows.ApplicationModel.Resources;
+#endif
-using RateMyApp.Helpers;
using RateMyApp.Resources;
namespace RateMyApp.Controls
@@ -36,16 +49,16 @@ namespace RateMyApp.Controls
public partial class FeedbackOverlay : UserControl
{
public static readonly DependencyProperty VisibilityForDesignProperty =
- DependencyProperty.Register("VisibilityForDesign", typeof(System.Windows.Visibility), typeof(FeedbackOverlay), new PropertyMetadata(System.Windows.Visibility.Collapsed, null));
+ DependencyProperty.Register("VisibilityForDesign", typeof(Visibility), typeof(FeedbackOverlay), new PropertyMetadata(Visibility.Collapsed, null));
- public static void SetVisibilityForDesign(FeedbackOverlay element, System.Windows.Visibility value)
+ public static void SetVisibilityForDesign(FeedbackOverlay element, Visibility value)
{
element.SetValue(VisibilityForDesignProperty, value);
}
- public static System.Windows.Visibility GetVisibilityForDesign(FeedbackOverlay element)
+ public static Visibility GetVisibilityForDesign(FeedbackOverlay element)
{
- return (System.Windows.Visibility)element.GetValue(VisibilityForDesignProperty);
+ return (Visibility)element.GetValue(VisibilityForDesignProperty);
}
// Use this from XAML to control whether animation is on or off
@@ -459,8 +472,10 @@ public static string GetLanguageOverride(FeedbackOverlay element)
// Use this for detecting visibility change on code
public event EventHandler VisibilityChanged = null;
+#if SILVERLIGHT
// PhoneApplicationFrame needed for detecting back presses
private PhoneApplicationFrame _rootFrame = null;
+#endif
// Title of the review/feedback notification
private string Title
@@ -614,11 +629,15 @@ private void FeedbackOverlay_Loaded(object sender, RoutedEventArgs e)
///
private void AttachBackKeyPressed()
{
+#if SILVERLIGHT
if (_rootFrame == null)
{
_rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
_rootFrame.BackKeyPress += FeedbackOverlay_BackKeyPress;
}
+#else
+ Windows.Phone.UI.Input.HardwareButtons.BackPressed += FeedbackOverlay_BackKeyPress;
+#endif
}
///
@@ -626,14 +645,22 @@ private void AttachBackKeyPressed()
///
///
///
+#if SILVERLIGHT
private void FeedbackOverlay_BackKeyPress(object sender, CancelEventArgs e)
+#else
+ private void FeedbackOverlay_BackKeyPress(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
+#endif
{
// If back is pressed whilst notification is open, close
// the notification and cancel back to stop app from exiting.
- if (Visibility == System.Windows.Visibility.Visible)
+ if (Visibility == Visibility.Visible)
{
OnNoClick();
+#if SILVERLIGHT
e.Cancel = true;
+#else
+ e.Handled = true;
+#endif
}
}
@@ -700,7 +727,11 @@ private void OnNoClick()
///
///
///
+#if SILVERLIGHT
private void hideContent_Completed(object sender, EventArgs e)
+#else
+ private void hideContent_Completed(object sender, object e)
+#endif
{
ShowFeedback();
}
@@ -757,19 +788,24 @@ private void yesButton_Click(object sender, RoutedEventArgs e)
///
private void Review()
{
- FeedbackHelper.Default.Reviewed();
+ FeedbackHelper.Default.Review();
- var marketplace = new MarketplaceReviewTask();
- marketplace.Show();
+ //var marketplace = new MarketplaceReviewTask();
+ //marketplace.Show();
}
///
/// Launch feedback email.
///
+#if SILVERLIGHT
private void Feedback()
+#else
+ private async void Feedback()
+#endif
{
string version = string.Empty;
+#if SILVERLIGHT
var appManifestResourceInfo = Application.GetResourceStream(new Uri("WMAppManifest.xml", UriKind.Relative));
using (var appManifestStream = appManifestResourceInfo.Stream)
@@ -796,6 +832,27 @@ private void Feedback()
var parts = asm.FullName.Split(',');
version = parts[1].Split('=')[1];
}
+#else
+ var uri = new System.Uri("ms-appx:///AppxManifest.xml");
+ StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
+ using (var rastream = await file.OpenReadAsync())
+ using (var appManifestStream = rastream.AsStreamForRead())
+ {
+ using (var reader = XmlReader.Create(appManifestStream, new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true }))
+ {
+ var doc = XDocument.Load(reader);
+ var app = doc.Descendants("Identity").FirstOrDefault();
+ if (app != null)
+ {
+ var versionAttribute = app.Attribute("Version");
+ if (versionAttribute != null)
+ {
+ version = versionAttribute.Value;
+ }
+ }
+ }
+ }
+#endif
string company = GetCompanyName(this);
if (company == null || company.Length <= 0)
@@ -803,6 +860,7 @@ private void Feedback()
company = "";
}
+#if SILVERLIGHT
// Body text including hardware, firmware and software info
string body = string.Format(FeedbackOverlay.GetFeedbackBody(this),
DeviceStatus.DeviceName,
@@ -819,6 +877,25 @@ private void Feedback()
email.Body = body;
email.Show();
+#else
+ var easClientDeviceInformation = new EasClientDeviceInformation();
+
+ // Body text including hardware, firmware and software info
+ string body = string.Format(FeedbackOverlay.GetFeedbackBody(this),
+ easClientDeviceInformation.SystemProductName,
+ easClientDeviceInformation.SystemManufacturer,
+ easClientDeviceInformation.SystemFirmwareVersion,
+ easClientDeviceInformation.SystemHardwareVersion,
+ version,
+ company);
+
+ // Send an Email with attachment
+ EmailMessage email = new EmailMessage();
+ email.To.Add(new EmailRecipient(FeedbackOverlay.GetFeedbackTo(this)));
+ email.Subject = string.Format(FeedbackOverlay.GetFeedbackSubject(this), GetApplicationName());
+ email.Body = body;
+ await EmailManager.ShowComposeNewEmailAsync(email);
+#endif
}
///
@@ -834,14 +911,14 @@ private void SetVisibility(bool visible)
PreparePanoramaPivot(false);
FeedbackOverlay.SetIsVisible(this, true);
FeedbackOverlay.SetIsNotVisible(this, false);
- Visibility = System.Windows.Visibility.Visible;
+ Visibility = Visibility.Visible;
}
else
{
PreparePanoramaPivot(true);
FeedbackOverlay.SetIsVisible(this, false);
FeedbackOverlay.SetIsNotVisible(this, true);
- Visibility = System.Windows.Visibility.Collapsed;
+ Visibility = Visibility.Collapsed;
}
if (wasVisible != visible)
@@ -894,11 +971,19 @@ private void PreparePanoramaPivot(bool hitTestVisible)
///
private void OverrideLanguage()
{
+#if SILVERLIGHT
CultureInfo originalCulture = Thread.CurrentThread.CurrentUICulture;
CultureInfo newCulture = new CultureInfo(GetLanguageOverride(this));
Thread.CurrentThread.CurrentCulture = newCulture;
Thread.CurrentThread.CurrentUICulture = newCulture;
+#else
+ CultureInfo originalCulture = CultureInfo.DefaultThreadCurrentUICulture;
+ CultureInfo newCulture = new CultureInfo(GetLanguageOverride(this));
+
+ CultureInfo.DefaultThreadCurrentCulture = newCulture;
+ CultureInfo.DefaultThreadCurrentUICulture = newCulture;
+#endif
SetFeedbackBody(this, AppResources.FeedbackBody);
SetFeedbackMessage1(this, string.Format(AppResources.FeedbackMessage1, GetApplicationName()));
@@ -912,8 +997,13 @@ private void OverrideLanguage()
SetRatingTitle(this, string.Format(AppResources.RatingTitle, GetApplicationName()));
SetRatingYes(this, AppResources.RatingYes);
+#if SILVERLIGHT
Thread.CurrentThread.CurrentCulture = originalCulture;
Thread.CurrentThread.CurrentUICulture = originalCulture;
+#else
+ CultureInfo.DefaultThreadCurrentCulture = originalCulture;
+ CultureInfo.DefaultThreadCurrentUICulture = originalCulture;
+#endif
}
///
diff --git a/RateMyApp/Controls/FeedbackOverlayXAML.xaml b/RateMyApp/Controls/FeedbackOverlayXAML.xaml
new file mode 100644
index 0000000..1b70536
--- /dev/null
+++ b/RateMyApp/Controls/FeedbackOverlayXAML.xaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RateMyApp/Helpers/FeedbackHelper.cs b/RateMyApp/Helpers/FeedbackHelper.cs
index 9589e43..535bbe1 100644
--- a/RateMyApp/Helpers/FeedbackHelper.cs
+++ b/RateMyApp/Helpers/FeedbackHelper.cs
@@ -9,11 +9,20 @@
* See the license text file delivered with this project for more information.
*/
-using Microsoft.Phone.Shell;
-using Microsoft.Phone.Tasks;
using System;
using System.ComponentModel;
using System.Diagnostics;
+#if SILVERLIGHT
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+#else
+using Windows.Storage;
+using System.Xml.Linq;
+using System.Xml;
+using System.IO;
+using System.Linq;
+#endif
+
namespace RateMyApp.Helpers
{
@@ -129,12 +138,20 @@ private FeedbackHelper()
///
public void Launching()
{
+#if SILVERLIGHT
var license = new Microsoft.Phone.Marketplace.LicenseInformation();
-
+#else
+ var license = Windows.ApplicationModel.Store.CurrentApp.LicenseInformation;
+#endif
// Only load state if app is not trial, app is not activated after
// being tombstoned, and state has not been loaded before.
+#if SILVERLIGHT
if (!license.IsTrial() &&
PhoneApplicationService.Current.StartupMode == StartupMode.Launch &&
+#else
+ if (!license.IsTrial &&
+#warning The app state is no longer checked, this needs a review
+#endif
State == FeedbackState.Active)
{
LoadState();
@@ -211,7 +228,12 @@ private void StoreState()
{
StorageHelper.StoreSetting(LaunchCountKey, LaunchCount, true);
StorageHelper.StoreSetting(ReviewedKey, reviewed, true);
+#if SILVERLIGHT
StorageHelper.StoreSetting(LastLaunchDateKey, lastLaunchDate, true);
+#else
+#warning Solution needed here
+ //StorageHelper.StoreSetting(LastLaunchDateKey, lastLaunchDate, true);
+#endif
}
catch (Exception ex)
{
@@ -228,12 +250,41 @@ protected void OnPropertyChanged(string name)
}
}
+#if SILVERLIGHT
public void Review()
+#else
+ public async void Review()
+#endif
{
Reviewed();
+#if SILVERLIGHT
var marketplace = new MarketplaceReviewTask();
marketplace.Show();
+#else
+ string appid = "";
+ var uri = new System.Uri("ms-appx:///AppxManifest.xml");
+ StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
+ using (var rastream = await file.OpenReadAsync())
+ using (var appManifestStream = rastream.AsStreamForRead())
+ {
+ using (var reader = XmlReader.Create(appManifestStream, new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true }))
+ {
+ var doc = XDocument.Load(reader);
+ var app = doc.Descendants().Where(e => e.Name.LocalName == "PhoneIdentity").FirstOrDefault();
+ if (app != null)
+ {
+ var idAttribute = app.Attribute("PhoneProductId");
+ if (idAttribute != null)
+ {
+ appid = idAttribute.Value;
+ }
+ }
+ }
+ }
+
+ await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-windows-store:reviewapp?appid=" + appid));
+#endif
}
}
}
diff --git a/RateMyApp/Helpers/StorageHelper.cs b/RateMyApp/Helpers/StorageHelper.cs
index 28a3b51..8b3122c 100644
--- a/RateMyApp/Helpers/StorageHelper.cs
+++ b/RateMyApp/Helpers/StorageHelper.cs
@@ -9,7 +9,9 @@
* See the license text file delivered with this project for more information.
*/
+#if SILVERLIGHT
using System.IO.IsolatedStorage;
+#endif
namespace RateMyApp.Helpers
{
@@ -28,12 +30,19 @@ public class StorageHelper
/// True if success, false otherwise.
public static bool StoreSetting(string key, object value, bool overwrite)
{
+#if SILVERLIGHT
if (overwrite || !IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
IsolatedStorageSettings.ApplicationSettings[key] = value;
return true;
}
-
+#else
+ if (overwrite || !Windows.Storage.ApplicationData.Current.LocalSettings.Values.ContainsKey(key))
+ {
+ Windows.Storage.ApplicationData.Current.LocalSettings.Values[key] = value;
+ return true;
+ }
+#endif
return false;
}
@@ -45,11 +54,17 @@ public static bool StoreSetting(string key, object value, bool overwrite)
/// The value for the key or a default value if key is not found.
public static T GetSetting(string key)
{
+#if SILVERLIGHT
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key];
}
-
+#else
+ if (Windows.Storage.ApplicationData.Current.LocalSettings.Values.ContainsKey(key))
+ {
+ return (T)Windows.Storage.ApplicationData.Current.LocalSettings.Values[key];
+ }
+#endif
return default(T);
}
@@ -61,11 +76,17 @@ public static T GetSetting(string key)
/// The value for the key or the default value if key is not found.
public static T GetSetting(string key, T defaultVal)
{
+#if SILVERLIGHT
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key];
}
-
+#else
+ if (Windows.Storage.ApplicationData.Current.LocalSettings.Values.ContainsKey(key))
+ {
+ return (T)Windows.Storage.ApplicationData.Current.LocalSettings.Values[key];
+ }
+#endif
return defaultVal;
}
@@ -75,7 +96,11 @@ public static T GetSetting(string key, T defaultVal)
///
public static void RemoveSetting(string key)
{
+#if SILVERLIGHT
IsolatedStorageSettings.ApplicationSettings.Remove(key);
+#else
+ Windows.Storage.ApplicationData.Current.LocalSettings.Values.Remove(key);
+#endif
}
}
}
diff --git a/RateMyApp/Properties/AssemblyInfo.cs b/RateMyApp/Properties/AssemblyInfo.cs
index 5ddded8..d97430d 100644
--- a/RateMyApp/Properties/AssemblyInfo.cs
+++ b/RateMyApp/Properties/AssemblyInfo.cs
@@ -20,9 +20,9 @@
[assembly: AssemblyTitle("RateMyApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Nokia")]
+[assembly: AssemblyCompany("Microsoft Mobile")]
[assembly: AssemblyProduct("RateMyApp")]
-[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -43,6 +43,6 @@
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.1.0.0")]
-[assembly: AssemblyFileVersion("1.1.0.0")]
+[assembly: AssemblyVersion("1.2.2.0")]
+[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: NeutralResourcesLanguageAttribute("en-US")]
diff --git a/RateMyApp/RateMyAppXAML.csproj b/RateMyApp/RateMyAppXAML.csproj
new file mode 100644
index 0000000..c68bf2b
--- /dev/null
+++ b/RateMyApp/RateMyAppXAML.csproj
@@ -0,0 +1,147 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {1F8048CE-C718-4CEB-A3B2-71F5D9EE411F}
+ Library
+ Properties
+ RateMyApp
+ RateMyApp
+ zh-CN%3bru-RU%3ben-GB%3bde-DE%3bro-RO%3bsl-SI%3bhr-HR%3bnl-NL%3bfi-FI%3bfr-FR%3bhe-IL%3bhu-HU%3bit-IT%3blt-LT%3bpl-PL%3bpt-BR%3bpt-PT%3buk-UA%3bvi-VN%3bsv-SE%3bnb-NO%3bes-ES%3bar-SA
+ en-US
+ 8.1
+ 12
+ 512
+ {76F1466A-8B6D-4E39-A767-685A06062A39};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ prompt
+ 4
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_PHONE_APP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+ FeedbackOverlayXAML.xaml
+
+
+
+
+
+
+ AppResources.resx
+ True
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PublicResXFileCodeGenerator
+ AppResources.Designer.cs
+
+
+
+
+
+
+
+
+
+
+ 12.0
+
+
+ WindowsPhoneApp
+
+
+
+
\ No newline at end of file
diff --git a/RateMyApp/Resources/AppResources.Designer.cs b/RateMyApp/Resources/AppResources.Designer.cs
index 8eb7103..d01cdff 100644
--- a/RateMyApp/Resources/AppResources.Designer.cs
+++ b/RateMyApp/Resources/AppResources.Designer.cs
@@ -10,7 +10,10 @@
namespace RateMyApp.Resources {
using System;
-
+#if SILVERLIGHT
+#else
+ using System.Reflection;
+#endif
///
/// A strongly-typed resource class, for looking up localized strings, etc.
@@ -39,7 +42,11 @@ public class AppResources {
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
+#if SILVERLIGHT
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RateMyApp.Resources.AppResources", typeof(AppResources).Assembly);
+#else
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RateMyApp.Resources.AppResources", typeof(AppResources).GetTypeInfo().Assembly);
+#endif
resourceMan = temp;
}
return resourceMan;
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml
new file mode 100644
index 0000000..a493332
--- /dev/null
+++ b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml.cs b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml.cs
new file mode 100644
index 0000000..9717550
--- /dev/null
+++ b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/App.xaml.cs
@@ -0,0 +1,141 @@
+using RateMyWindowsRuntimeXAMLHubApp.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Media.Animation;
+using Windows.UI.Xaml.Navigation;
+
+// The Hub Application template is documented at http://go.microsoft.com/fwlink/?LinkId=391641
+
+namespace RateMyWindowsRuntimeXAMLHubApp
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public sealed partial class App : Application
+ {
+ private TransitionCollection transitions;
+
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ this.Suspending += this.OnSuspending;
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used when the application is launched to open a specific file, to display
+ /// search results, and so forth.
+ ///
+ /// Details about the launch request and process.
+ protected override async void OnLaunched(LaunchActivatedEventArgs e)
+ {
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ this.DebugSettings.EnableFrameRateCounter = true;
+ }
+#endif
+
+ Frame rootFrame = Window.Current.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active.
+ if (rootFrame == null)
+ {
+ // Create a Frame to act as the navigation context and navigate to the first page.
+ rootFrame = new Frame();
+
+ // Associate the frame with a SuspensionManager key.
+ SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
+
+ // TODO: Change this value to a cache size that is appropriate for your application.
+ rootFrame.CacheSize = 1;
+
+ if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
+ {
+ // Restore the saved session state only when appropriate.
+ try
+ {
+ await SuspensionManager.RestoreAsync();
+ }
+ catch (SuspensionManagerException)
+ {
+ // Something went wrong restoring state.
+ // Assume there is no state and continue.
+ }
+ }
+
+ // Place the frame in the current Window.
+ Window.Current.Content = rootFrame;
+ }
+
+ if (rootFrame.Content == null)
+ {
+ // Removes the turnstile navigation for startup.
+ if (rootFrame.ContentTransitions != null)
+ {
+ this.transitions = new TransitionCollection();
+ foreach (var c in rootFrame.ContentTransitions)
+ {
+ this.transitions.Add(c);
+ }
+ }
+
+ rootFrame.ContentTransitions = null;
+ rootFrame.Navigated += this.RootFrame_FirstNavigated;
+
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter.
+ if (!rootFrame.Navigate(typeof(HubPage), e.Arguments))
+ {
+ throw new Exception("Failed to create initial page");
+ }
+ }
+
+ // Ensure the current window is active.
+ Window.Current.Activate();
+ }
+
+ ///
+ /// Restores the content transitions after the app has launched.
+ ///
+ private void RootFrame_FirstNavigated(object sender, NavigationEventArgs e)
+ {
+ var rootFrame = sender as Frame;
+ rootFrame.ContentTransitions = this.transitions ?? new TransitionCollection() { new NavigationThemeTransition() };
+ rootFrame.Navigated -= this.RootFrame_FirstNavigated;
+ }
+
+ ///
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ ///
+ /// The source of the suspend request.
+ /// Details about the suspend request.
+ private async void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ var deferral = e.SuspendingOperation.GetDeferral();
+ await SuspensionManager.SaveAsync();
+ deferral.Complete();
+ }
+ }
+}
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/DarkGray.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/DarkGray.png
new file mode 100644
index 0000000..6cb268a
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/DarkGray.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-dark.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-dark.png
new file mode 100644
index 0000000..1c44867
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-dark.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-light.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-light.png
new file mode 100644
index 0000000..d423930
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/HubBackground.theme-light.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/LightGray.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/LightGray.png
new file mode 100644
index 0000000..6ccc22b
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/LightGray.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Logo.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Logo.scale-240.png
new file mode 100644
index 0000000..76921ca
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Logo.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/MediumGray.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/MediumGray.png
new file mode 100644
index 0000000..cadb696
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/MediumGray.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SmallLogo.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SmallLogo.scale-240.png
new file mode 100644
index 0000000..3166301
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SmallLogo.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SplashScreen.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SplashScreen.scale-240.png
new file mode 100644
index 0000000..33f26b3
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/SplashScreen.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Square71x71Logo.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Square71x71Logo.scale-240.png
new file mode 100644
index 0000000..cfa54be
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/Square71x71Logo.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/StoreLogo.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/StoreLogo.scale-240.png
new file mode 100644
index 0000000..47e084b
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/StoreLogo.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/WideLogo.scale-240.png b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/WideLogo.scale-240.png
new file mode 100644
index 0000000..6249d29
Binary files /dev/null and b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Assets/WideLogo.scale-240.png differ
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/NavigationHelper.cs b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/NavigationHelper.cs
new file mode 100644
index 0000000..0e7b3dc
--- /dev/null
+++ b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/NavigationHelper.cs
@@ -0,0 +1,436 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Windows.System;
+using Windows.UI.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Navigation;
+
+namespace RateMyWindowsRuntimeXAMLHubApp.Common
+{
+ ///
+ /// NavigationHelper aids in navigation between pages. It provides commands used to
+ /// navigate back and forward as well as registers for standard mouse and keyboard
+ /// shortcuts used to go back and forward in Windows and the hardware back button in
+ /// Windows Phone. In addition it integrates SuspensionManger to handle process lifetime
+ /// management and state management when navigating between pages.
+ ///
+ ///
+ /// To make use of NavigationHelper, follow these two steps or
+ /// start with a BasicPage or any other Page item template other than BlankPage.
+ ///
+ /// 1) Create an instance of the NavigationHelper somewhere such as in the
+ /// constructor for the page and register a callback for the LoadState and
+ /// SaveState events.
+ ///
+ /// public MyPage()
+ /// {
+ /// this.InitializeComponent();
+ /// var navigationHelper = new NavigationHelper(this);
+ /// this.navigationHelper.LoadState += navigationHelper_LoadState;
+ /// this.navigationHelper.SaveState += navigationHelper_SaveState;
+ /// }
+ ///
+ /// private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
+ /// { }
+ /// private async void navigationHelper_SaveState(object sender, LoadStateEventArgs e)
+ /// { }
+ ///
+ ///
+ /// 2) Register the page to call into the NavigationHelper whenever the page participates
+ /// in navigation by overriding the
+ /// and events.
+ ///
+ /// protected override void OnNavigatedTo(NavigationEventArgs e)
+ /// {
+ /// navigationHelper.OnNavigatedTo(e);
+ /// }
+ ///
+ /// protected override void OnNavigatedFrom(NavigationEventArgs e)
+ /// {
+ /// navigationHelper.OnNavigatedFrom(e);
+ /// }
+ ///
+ ///
+ [Windows.Foundation.Metadata.WebHostHidden]
+ public class NavigationHelper : DependencyObject
+ {
+ private Page Page { get; set; }
+ private Frame Frame { get { return this.Page.Frame; } }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A reference to the current page used for navigation.
+ /// This reference allows for frame manipulation and to ensure that keyboard
+ /// navigation requests only occur when the page is occupying the entire window.
+ public NavigationHelper(Page page)
+ {
+ this.Page = page;
+
+ // When this page is part of the visual tree make two changes:
+ // 1) Map application view state to visual state for the page
+ // 2) Handle hardware navigation requests
+ this.Page.Loaded += (sender, e) =>
+ {
+#if WINDOWS_PHONE_APP
+ Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
+#else
+ // Keyboard and mouse navigation only apply when occupying the entire window
+ if (this.Page.ActualHeight == Window.Current.Bounds.Height &&
+ this.Page.ActualWidth == Window.Current.Bounds.Width)
+ {
+ // Listen to the window directly so focus isn't required
+ Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
+ CoreDispatcher_AcceleratorKeyActivated;
+ Window.Current.CoreWindow.PointerPressed +=
+ this.CoreWindow_PointerPressed;
+ }
+#endif
+ };
+
+ // Undo the same changes when the page is no longer visible
+ this.Page.Unloaded += (sender, e) =>
+ {
+#if WINDOWS_PHONE_APP
+ Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
+#else
+ Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -=
+ CoreDispatcher_AcceleratorKeyActivated;
+ Window.Current.CoreWindow.PointerPressed -=
+ this.CoreWindow_PointerPressed;
+#endif
+ };
+ }
+
+ #region Navigation support
+
+ RelayCommand _goBackCommand;
+ RelayCommand _goForwardCommand;
+
+ ///
+ /// used to bind to the back Button's Command property
+ /// for navigating to the most recent item in back navigation history, if a Frame
+ /// manages its own navigation history.
+ ///
+ /// The is set up to use the virtual method
+ /// as the Execute Action and for CanExecute.
+ ///
+ public RelayCommand GoBackCommand
+ {
+ get
+ {
+ if (_goBackCommand == null)
+ {
+ _goBackCommand = new RelayCommand(
+ () => this.GoBack(),
+ () => this.CanGoBack());
+ }
+ return _goBackCommand;
+ }
+ set
+ {
+ _goBackCommand = value;
+ }
+ }
+ ///
+ /// used for navigating to the most recent item in
+ /// the forward navigation history, if a Frame manages its own navigation history.
+ ///
+ /// The is set up to use the virtual method
+ /// as the Execute Action and for CanExecute.
+ ///
+ public RelayCommand GoForwardCommand
+ {
+ get
+ {
+ if (_goForwardCommand == null)
+ {
+ _goForwardCommand = new RelayCommand(
+ () => this.GoForward(),
+ () => this.CanGoForward());
+ }
+ return _goForwardCommand;
+ }
+ }
+
+ ///
+ /// Virtual method used by the property
+ /// to determine if the can go back.
+ ///
+ ///
+ /// true if the has at least one entry
+ /// in the back navigation history.
+ ///
+ public virtual bool CanGoBack()
+ {
+ return this.Frame != null && this.Frame.CanGoBack;
+ }
+ ///
+ /// Virtual method used by the property
+ /// to determine if the can go forward.
+ ///
+ ///
+ /// true if the has at least one entry
+ /// in the forward navigation history.
+ ///
+ public virtual bool CanGoForward()
+ {
+ return this.Frame != null && this.Frame.CanGoForward;
+ }
+
+ ///
+ /// Virtual method used by the property
+ /// to invoke the method.
+ ///
+ public virtual void GoBack()
+ {
+ if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
+ }
+ ///
+ /// Virtual method used by the property
+ /// to invoke the method.
+ ///
+ public virtual void GoForward()
+ {
+ if (this.Frame != null && this.Frame.CanGoForward) this.Frame.GoForward();
+ }
+
+#if WINDOWS_PHONE_APP
+ ///
+ /// Invoked when the hardware back button is pressed. For Windows Phone only.
+ ///
+ /// Instance that triggered the event.
+ /// Event data describing the conditions that led to the event.
+ private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
+ {
+ if (this.GoBackCommand.CanExecute(null))
+ {
+ e.Handled = true;
+ this.GoBackCommand.Execute(null);
+ }
+ }
+#else
+ ///
+ /// Invoked on every keystroke, including system keys such as Alt key combinations, when
+ /// this page is active and occupies the entire window. Used to detect keyboard navigation
+ /// between pages even when the page itself doesn't have focus.
+ ///
+ /// Instance that triggered the event.
+ /// Event data describing the conditions that led to the event.
+ private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender,
+ AcceleratorKeyEventArgs e)
+ {
+ var virtualKey = e.VirtualKey;
+
+ // Only investigate further when Left, Right, or the dedicated Previous or Next keys
+ // are pressed
+ if ((e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown ||
+ e.EventType == CoreAcceleratorKeyEventType.KeyDown) &&
+ (virtualKey == VirtualKey.Left || virtualKey == VirtualKey.Right ||
+ (int)virtualKey == 166 || (int)virtualKey == 167))
+ {
+ var coreWindow = Window.Current.CoreWindow;
+ var downState = CoreVirtualKeyStates.Down;
+ bool menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState;
+ bool controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState;
+ bool shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState;
+ bool noModifiers = !menuKey && !controlKey && !shiftKey;
+ bool onlyAlt = menuKey && !controlKey && !shiftKey;
+
+ if (((int)virtualKey == 166 && noModifiers) ||
+ (virtualKey == VirtualKey.Left && onlyAlt))
+ {
+ // When the previous key or Alt+Left are pressed navigate back
+ e.Handled = true;
+ this.GoBackCommand.Execute(null);
+ }
+ else if (((int)virtualKey == 167 && noModifiers) ||
+ (virtualKey == VirtualKey.Right && onlyAlt))
+ {
+ // When the next key or Alt+Right are pressed navigate forward
+ e.Handled = true;
+ this.GoForwardCommand.Execute(null);
+ }
+ }
+ }
+
+ ///
+ /// Invoked on every mouse click, touch screen tap, or equivalent interaction when this
+ /// page is active and occupies the entire window. Used to detect browser-style next and
+ /// previous mouse button clicks to navigate between pages.
+ ///
+ /// Instance that triggered the event.
+ /// Event data describing the conditions that led to the event.
+ private void CoreWindow_PointerPressed(CoreWindow sender,
+ PointerEventArgs e)
+ {
+ var properties = e.CurrentPoint.Properties;
+
+ // Ignore button chords with the left, right, and middle buttons
+ if (properties.IsLeftButtonPressed || properties.IsRightButtonPressed ||
+ properties.IsMiddleButtonPressed) return;
+
+ // If back or foward are pressed (but not both) navigate appropriately
+ bool backPressed = properties.IsXButton1Pressed;
+ bool forwardPressed = properties.IsXButton2Pressed;
+ if (backPressed ^ forwardPressed)
+ {
+ e.Handled = true;
+ if (backPressed) this.GoBackCommand.Execute(null);
+ if (forwardPressed) this.GoForwardCommand.Execute(null);
+ }
+ }
+#endif
+
+ #endregion
+
+ #region Process lifetime management
+
+ private String _pageKey;
+
+ ///
+ /// Register this event on the current page to populate the page
+ /// with content passed during navigation as well as any saved
+ /// state provided when recreating a page from a prior session.
+ ///
+ public event LoadStateEventHandler LoadState;
+ ///
+ /// Register this event on the current page to preserve
+ /// state associated with the current page in case the
+ /// application is suspended or the page is discarded from
+ /// the navigaqtion cache.
+ ///
+ public event SaveStateEventHandler SaveState;
+
+ ///
+ /// Invoked when this page is about to be displayed in a Frame.
+ /// This method calls , where all page specific
+ /// navigation and process lifetime management logic should be placed.
+ ///
+ /// Event data that describes how this page was reached. The Parameter
+ /// property provides the group to be displayed.
+ public void OnNavigatedTo(NavigationEventArgs e)
+ {
+ var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
+ this._pageKey = "Page-" + this.Frame.BackStackDepth;
+
+ if (e.NavigationMode == NavigationMode.New)
+ {
+ // Clear existing state for forward navigation when adding a new page to the
+ // navigation stack
+ var nextPageKey = this._pageKey;
+ int nextPageIndex = this.Frame.BackStackDepth;
+ while (frameState.Remove(nextPageKey))
+ {
+ nextPageIndex++;
+ nextPageKey = "Page-" + nextPageIndex;
+ }
+
+ // Pass the navigation parameter to the new page
+ if (this.LoadState != null)
+ {
+ this.LoadState(this, new LoadStateEventArgs(e.Parameter, null));
+ }
+ }
+ else
+ {
+ // Pass the navigation parameter and preserved page state to the page, using
+ // the same strategy for loading suspended state and recreating pages discarded
+ // from cache
+ if (this.LoadState != null)
+ {
+ this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary)frameState[this._pageKey]));
+ }
+ }
+ }
+
+ ///
+ /// Invoked when this page will no longer be displayed in a Frame.
+ /// This method calls , where all page specific
+ /// navigation and process lifetime management logic should be placed.
+ ///
+ /// Event data that describes how this page was reached. The Parameter
+ /// property provides the group to be displayed.
+ public void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
+ var pageState = new Dictionary();
+ if (this.SaveState != null)
+ {
+ this.SaveState(this, new SaveStateEventArgs(pageState));
+ }
+ frameState[_pageKey] = pageState;
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Represents the method that will handle the event
+ ///
+ public delegate void LoadStateEventHandler(object sender, LoadStateEventArgs e);
+ ///
+ /// Represents the method that will handle the event
+ ///
+ public delegate void SaveStateEventHandler(object sender, SaveStateEventArgs e);
+
+ ///
+ /// Class used to hold the event data required when a page attempts to load state.
+ ///
+ public class LoadStateEventArgs : EventArgs
+ {
+ ///
+ /// The parameter value passed to
+ /// when this page was initially requested.
+ ///
+ public Object NavigationParameter { get; private set; }
+ ///
+ /// A dictionary of state preserved by this page during an earlier
+ /// session. This will be null the first time a page is visited.
+ ///
+ public Dictionary PageState { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The parameter value passed to
+ /// when this page was initially requested.
+ ///
+ ///
+ /// A dictionary of state preserved by this page during an earlier
+ /// session. This will be null the first time a page is visited.
+ ///
+ public LoadStateEventArgs(Object navigationParameter, Dictionary pageState)
+ : base()
+ {
+ this.NavigationParameter = navigationParameter;
+ this.PageState = pageState;
+ }
+ }
+ ///
+ /// Class used to hold the event data required when a page attempts to save state.
+ ///
+ public class SaveStateEventArgs : EventArgs
+ {
+ ///
+ /// An empty dictionary to be populated with serializable state.
+ ///
+ public Dictionary PageState { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An empty dictionary to be populated with serializable state.
+ public SaveStateEventArgs(Dictionary pageState)
+ : base()
+ {
+ this.PageState = pageState;
+ }
+ }
+}
diff --git a/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/ObservableDictionary.cs b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/ObservableDictionary.cs
new file mode 100644
index 0000000..878565c
--- /dev/null
+++ b/RateMyAppDemos/WP81/Windows Runtime/RateMyWindowsRuntimeXAMLHubApp/Common/ObservableDictionary.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Windows.Foundation.Collections;
+
+namespace RateMyWindowsRuntimeXAMLHubApp.Common
+{
+ ///
+ /// Implementation of IObservableMap that supports reentrancy for use as a default view
+ /// model.
+ ///
+ public class ObservableDictionary : IObservableMap
+ {
+ private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs
+ {
+ public ObservableDictionaryChangedEventArgs(CollectionChange change, string key)
+ {
+ this.CollectionChange = change;
+ this.Key = key;
+ }
+
+ public CollectionChange CollectionChange { get; private set; }
+ public string Key { get; private set; }
+ }
+
+ private Dictionary _dictionary = new Dictionary();
+ public event MapChangedEventHandler MapChanged;
+
+ private void InvokeMapChanged(CollectionChange change, string key)
+ {
+ var eventHandler = MapChanged;
+ if (eventHandler != null)
+ {
+ eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key));
+ }
+ }
+
+ public void Add(string key, object value)
+ {
+ this._dictionary.Add(key, value);
+ this.InvokeMapChanged(CollectionChange.ItemInserted, key);
+ }
+
+ public void Add(KeyValuePair item)
+ {
+ this.Add(item.Key, item.Value);
+ }
+
+ public bool Remove(string key)
+ {
+ if (this._dictionary.Remove(key))
+ {
+ this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
+ return true;
+ }
+ return false;
+ }
+
+ public bool Remove(KeyValuePair item)
+ {
+ object currentValue;
+ if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
+ Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
+ {
+ this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
+ return true;
+ }
+ return false;
+ }
+
+ public object this[string key]
+ {
+ get
+ {
+ return this._dictionary[key];
+ }
+ set
+ {
+ this._dictionary[key] = value;
+ this.InvokeMapChanged(CollectionChange.ItemChanged, key);
+ }
+ }
+
+ public void Clear()
+ {
+ var priorKeys = this._dictionary.Keys.ToArray();
+ this._dictionary.Clear();
+ foreach (var key in priorKeys)
+ {
+ this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
+ }
+ }
+
+ public ICollection Keys
+ {
+ get { return this._dictionary.Keys; }
+ }
+
+ public bool ContainsKey(string key)
+ {
+ return this._dictionary.ContainsKey(key);
+ }
+
+ public bool TryGetValue(string key, out object value)
+ {
+ return this._dictionary.TryGetValue(key, out value);
+ }
+
+ public ICollection