diff --git a/main/Libs/PushRecipe_WP7_SL/Images/Class Digram.png b/main/Libs/PushRecipe_WP7_SL/Images/Class Digram.png
new file mode 100644
index 0000000..4d81d9e
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Images/Class Digram.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/Libraries.csproj b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/Libraries.csproj
new file mode 100644
index 0000000..98a9240
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/Libraries.csproj
@@ -0,0 +1,56 @@
+
+
+
+ Debug
+ x86
+ 8.0.30703
+ 2.0
+ {33915750-A749-4D9D-A5E9-E1B01773D724}
+ Exe
+ Properties
+ Libraries
+ Libraries
+ v4.0
+ Client
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.Design.dll b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.Design.dll
new file mode 100644
index 0000000..7ef11eb
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.Design.dll differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.dll b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.dll
new file mode 100644
index 0000000..8779ae8
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.dll differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.pdb b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.pdb
new file mode 100644
index 0000000..140a186
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.pdb differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.xml b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.xml
new file mode 100644
index 0000000..daf19a3
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WP7_Toolkit/Microsoft.Phone.Controls.Toolkit.xml
@@ -0,0 +1,2713 @@
+
+
+
+ Microsoft.Phone.Controls.Toolkit
+
+
+
+
+ The ItemContainerGenerator provides useful utilities for ItemsControls.
+
+ Preview
+
+
+
+ A Panel that is used as the ItemsHost of the ItemsControl. This
+ property will only be valid when the ItemsControl is live in the
+ tree and has generated containers for some of its items.
+
+
+
+
+ A ScrollViewer that is used to scroll the items in the ItemsHost.
+
+
+
+
+ Initializes a new instance of the ItemContainerGenerator.
+
+
+ The ItemsControl being tracked by the ItemContainerGenerator.
+
+
+
+
+ Apply a control template to the ItemsControl.
+
+
+
+
+ Prepares the specified container to display the specified item.
+
+
+ Container element used to display the specified item.
+
+
+ The ItemContainerStyle for the parent ItemsControl.
+
+
+
+
+ Update the style of any generated items when the ItemContainerStyle
+ has been changed.
+
+ The ItemContainerStyle.
+
+ Silverlight does not support setting a Style multiple times, so we
+ only attempt to set styles on elements whose style hasn't already
+ been set.
+
+
+
+
+ Scroll the desired element into the ScrollHost's viewport.
+
+ Element to scroll into view.
+
+
+
+ Gets or sets the ItemsControl being tracked by the
+ ItemContainerGenerator.
+
+
+
+
+ Gets a Panel that is used as the ItemsHost of the ItemsControl.
+ This property will only be valid when the ItemsControl is live in
+ the tree and has generated containers for some of its items.
+
+
+
+
+ Gets a ScrollViewer that is used to scroll the items in the
+ ItemsHost.
+
+
+
+
+ Converts instances of other types to and from instances of a double that
+ represent an object measurement such as a height or width.
+
+ Stable
+
+
+
+ Conversions from units to pixels.
+
+
+
+
+ Initializes a new instance of the
+ class.
+
+
+
+
+ Determines whether conversion is possible from a specified type to a
+ that represents an object
+ measurement.
+
+
+ An
+ that provides a format context.
+
+
+ A that represents the type you want to
+ convert from.
+
+
+ True if this converter can perform the conversion; otherwise, false.
+
+
+
+
+ Converts from the specified value to values of the
+ type.
+
+
+ An
+ that provides a format context.
+
+
+ The to use as the
+ current culture.
+
+ The value to convert.
+ The converted value.
+
+
+
+ Returns whether the type converter can convert a measurement to the
+ specified type.
+
+
+ An
+ that provides a format context.
+
+
+ A that represents the type you want to
+ convert to.
+
+
+ True if this converter can perform the conversion; otherwise, false.
+
+
+
+
+ Converts the specified measurement to the specified type.
+
+
+ An object that provides a format context.
+
+
+ The to use as the
+ current culture.
+
+ The value to convert.
+
+ A that represents the type you want to
+ convert to.
+
+ The converted value.
+
+
+
+ Return the angle of the hypotenuse of a triangle with
+ sides defined by deltaX and deltaY.
+
+ Change in X.
+ Change in Y.
+ The angle (in degrees).
+
+
+
+ Return the distance between two points
+
+ The first point.
+ The second point.
+ The distance between the two points.
+
+
+
+ Helper extension method for turning XNA's Vector2 type into a Point
+
+ The Vector2.
+ The point.
+
+
+
+ Numeric utility methods used by controls. These methods are similar in
+ scope to the WPF DoubleUtil class.
+
+
+
+
+ Check if a number isn't really a number.
+
+ The number to check.
+
+ True if the number is not a number, false if it is a number.
+
+
+
+
+ Determine if one number is greater than another.
+
+ First number.
+ Second number.
+
+ True if the first number is greater than the second, false
+ otherwise.
+
+
+
+
+ Determine if two numbers are close in value.
+
+ First number.
+ Second number.
+
+ True if the first number is close in value to the second, false
+ otherwise.
+
+
+
+
+ NanUnion is a C++ style type union used for efficiently converting
+ a double into an unsigned long, whose bits can be easily
+ manipulated.
+
+
+
+
+ Floating point representation of the union.
+
+
+
+
+ Integer representation of the union.
+
+
+
+
+ A helper class for raising events safely.
+
+
+
+
+ Raises an event in a thread-safe manner, also does the null check.
+
+ The event to raise.
+ The event sender.
+
+
+
+ Raises an event in a thread-safe manner, also does the null check.
+
+ The event args type.
+ The event to raise.
+ The event sender.
+ The event args.
+
+
+
+ Raise an event in a thread-safe manner, with the required null check. Lazily creates event args.
+
+ The event args type.
+ The event to raise.
+ The event sender.
+ The delegate to return the event args if needed.
+
+
+
+ This is a method that returns event args, used for lazy creation.
+
+ The event type.
+
+
+
+
+ Allows time to be set from xaml.
+
+ Preview
+ This converter is used by xaml and thus uses the
+ English formats.
+
+
+
+ BackingField for the TimeFormats being used.
+
+
+
+
+ BackingField for the DateFormats being used.
+
+
+
+
+ Determines whether this instance can convert from
+ the specified type descriptor context.
+
+ The type descriptor context.
+ Type of the source.
+
+ True if this instance can convert from the specified type
+ descriptor context; otherwise, false.
+
+
+
+
+ Determines whether this instance can convert to the specified
+ type descriptor context.
+
+ The type descriptor context.
+ Type of the destination.
+
+ True if this instance can convert to the specified type
+ descriptor context; otherwise, false.
+
+
+
+
+ Converts instances of other data types into instances of DateTime that
+ represent a time.
+
+
+ The type descriptor context.
+
+ The culture used to convert. This culture
+ is not used during conversion, but a specific set of formats is used.
+
+ The string being converted to the DateTime.
+
+
+ A DateTime that is the value of the conversion.
+
+
+
+
+ Converts a DateTime into a string.
+
+
+ The type descriptor context.
+
+ The culture used to convert.
+
+ The value that is being converted to a specified type.
+
+
+ The type to convert the value to.
+
+
+ The value of the conversion to the specified type.
+
+
+
+
+ Represents a 2-tuple, or pair.
+
+ The type of the tuple's first component.
+ The type of the tuple's second component.
+
+
+
+ Initializes a new instance of the Tuple(T1, T2) class.
+
+ The value of the tuple's first component.
+ The value of the tuple's second component.
+
+
+
+ Gets the value of the current Tuple(T1, T2) object's first component.
+
+
+
+
+ Gets the value of the current Tuple(T1, T2) object's second component.
+
+
+
+
+ Common TypeConverter functionality.
+
+
+
+
+ Determines whether conversion is possible to a specified type.
+
+ Expected type of the converter.
+
+ Identifies the data type to evaluate for conversion.
+
+
+ A value indicating whether conversion is possible.
+
+
+
+
+ Attempts to convert a specified object to an instance of the
+ desired type.
+
+ TypeConverter instance.
+ The object being converted.
+
+ The type to convert the value to.
+
+
+ The value of the conversion to the specified type.
+
+
+
+
+ Represents a pop-up menu that enables a control to expose functionality that is specific to the context of the control.
+
+ Preview
+
+
+
+ Represents a control that defines choices for users to select.
+
+ Preview
+
+
+
+ Identifies the ItemContainerStyle dependency property.
+
+
+
+
+ Initializes a new instance of the MenuBase class.
+
+
+
+
+ Determines whether the specified item is, or is eligible to be, its own item container.
+
+ The item to check whether it is an item container.
+ True if the item is a MenuItem or a Separator; otherwise, false.
+
+
+
+ Creates or identifies the element used to display the specified item.
+
+ A MenuItem.
+
+
+
+ Prepares the specified element to display the specified item.
+
+ Element used to display the specified item.
+ Specified item.
+
+
+
+ Checks whether a control has the default value for a property.
+
+ The control to check.
+ The property to check.
+ True if the property has the default value; false otherwise.
+
+
+
+ Gets or sets the Style that is applied to the container element generated for each item.
+
+
+
+
+ Visibility state group.
+
+
+
+
+ Open visibility state.
+
+
+
+
+ Closed visibility state.
+
+
+
+
+ Stores a reference to the PhoneApplicationPage that contains the owning object.
+
+
+
+
+ Stores a reference to a list of ApplicationBarIconButtons for which the Click event is being handled.
+
+
+
+
+ Stores a reference to the Storyboard used to animate the background resize.
+
+
+
+
+ Stores a reference to the Storyboard used to animate the ContextMenu open.
+
+
+
+
+ Tracks whether the Storyboard used to animate the ContextMenu open is active.
+
+
+
+
+ Tracks the threshold for releasing contact during the ContextMenu open animation.
+
+
+
+
+ Stores a reference to the timer used to detect the tap+hold gesture that opens the ContextMenu.
+
+
+
+
+ Tracks the start point for manipulation events (in root-relative coordinates).
+
+
+
+
+ Stores a reference to the current root visual.
+
+
+
+
+ Stores the last known mouse position (via MouseMove).
+
+
+
+
+ Stores a reference to the object that owns the ContextMenu.
+
+
+
+
+ Stores a reference to the current Popup.
+
+
+
+
+ Stores a reference to the current overlay.
+
+
+
+
+ Stores a reference to the current Popup alignment point.
+
+
+
+
+ Stores a value indicating whether the IsOpen property is being updated by ContextMenu.
+
+
+
+
+ Identifies the IsZoomEnabled dependency property.
+
+
+
+
+ Identifies the VerticalOffset dependency property.
+
+
+
+
+ Handles changes to the HorizontalOffset or VerticalOffset DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Identifies the IsOpen dependency property.
+
+
+
+
+ Handles changes to the IsOpen DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Handles changes to the IsOpen property.
+
+ New value.
+
+
+
+ Called when the Opened event occurs.
+
+ Event arguments.
+
+
+
+ Called when the Closed event occurs.
+
+ Event arguments.
+
+
+
+ Initializes a new instance of the ContextMenu class.
+
+
+
+
+ Called when a new Template is applied.
+
+
+
+
+ Handles the Completed event of the opening Storyboard.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Uses VisualStateManager to go to a new visual state.
+
+ The state to transition to.
+ true to use a System.Windows.VisualTransition to transition between states; otherwise, false.
+
+
+
+ Called when the left mouse button is pressed.
+
+ The event data for the MouseLeftButtonDown event.
+
+
+
+ Responds to the KeyDown event.
+
+ The event data for the KeyDown event.
+
+
+
+ Handles the LayoutUpdated event to capture Application.Current.RootVisual.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the RootVisual's MouseMove event to track the last mouse position.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the ManipulationCompleted event for the RootVisual.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the ManipulationStarted event of the Owner element.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the ManipulationDelta or ManipulationCompleted events of the Owner element.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the Tick event of the DispatcherTimer for tap+hold detection.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Identifies the ApplicationBarMirror dependency property.
+
+
+
+
+ Handles changes to the ApplicationBarMirror DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Handles changes to the ApplicationBarMirror property.
+
+ Old value.
+ New value.
+
+
+
+ Handles an event which should close an open ContextMenu.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the Loaded event of the Owner.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the Unloaded event of the Owner.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the BackKeyPress of the containing PhoneApplicationPage.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Initialize the _rootVisual property (if possible and not already done).
+
+
+
+
+ Sets focus to the next item in the ContextMenu.
+
+ True to move the focus down; false to move it up.
+
+
+
+ Called when a child MenuItem is clicked.
+
+
+
+
+ Handles the SizeChanged event for the ContextMenu or RootVisual.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Handles the MouseButtonDown events for the overlay.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Updates the location and size of the Popup and overlay.
+
+
+
+
+ Opens the Popup.
+
+ Position to place the Popup.
+
+
+
+ Closes the Popup.
+
+
+
+
+ Gets or sets the owning object for the ContextMenu.
+
+
+
+
+ Gets or sets a value indicating whether the background will zoom out when the ContextMenu is open.
+
+
+
+
+ Gets or sets the vertical distance between the target origin and the popup alignment point.
+
+
+
+
+ Gets or sets a value indicating whether the ContextMenu is visible.
+
+
+
+
+ Occurs when a particular instance of a ContextMenu opens.
+
+
+
+
+ Occurs when a particular instance of a ContextMenu closes.
+
+
+
+
+ Provides the system implementation for displaying a ContextMenu.
+
+ Preview
+
+
+
+ Gets the value of the ContextMenu property of the specified object.
+
+ Object to query concerning the ContextMenu property.
+ Value of the ContextMenu property.
+
+
+
+ Sets the value of the ContextMenu property of the specified object.
+
+ Object to set the property on.
+ Value to set.
+
+
+
+ Identifies the ContextMenu attached property.
+
+
+
+
+ Handles changes to the ContextMenu DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Represents a selectable item inside a Menu or ContextMenu.
+
+ Preview
+
+
+
+ Represents a control that contains a collection of items and a header.
+
+ Stable
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property.
+
+
+ Note: WPF defines this property via a call to AddOwner of
+ HeaderedContentControl's HeaderProperty.
+
+
+
+
+ HeaderProperty property changed handler.
+
+
+ HeaderedItemsControl that changed its Header.
+
+ Event arguments.
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property.
+
+
+ Note: WPF defines this property via a call to AddOwner of
+ HeaderedContentControl's HeaderTemplateProperty.
+
+
+
+
+ HeaderTemplateProperty property changed handler.
+
+
+ HeaderedItemsControl that changed its HeaderTemplate.
+
+ Event arguments.
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property.
+
+
+
+
+ ItemContainerStyleProperty property changed handler.
+
+
+ HeaderedItemsControl that changed its ItemContainerStyle.
+
+ Event arguments.
+
+
+
+ Initializes a new instance of the
+ class.
+
+
+
+
+ Called when the value of the
+
+ property changes.
+
+
+ The old value of the
+
+ property.
+
+
+ The new value of the
+
+ property.
+
+
+
+
+ Called when the value of the
+
+ property changes.
+
+
+ The old value of the
+
+ property.
+
+
+ The new value of the
+
+ property.
+
+
+
+
+ Builds the visual tree for the
+ when a
+ new template is applied.
+
+
+
+
+ Prepares the specified element to display the specified item.
+
+
+ The container element used to display the specified item.
+
+ The content to display.
+
+
+
+ Prepares the specified container to display the specified item.
+
+
+ Container element used to display the specified item.
+
+ Specified item to display.
+ The parent ItemsControl.
+
+ The ItemContainerStyle for the parent ItemsControl.
+
+
+
+
+ Prepare a PrepareHeaderedItemsControlContainer container for an
+ item.
+
+ Container to prepare.
+ Item to be placed in the container.
+ The parent ItemsControl.
+
+ The ItemContainerStyle for the parent ItemsControl.
+
+
+
+
+ Check whether a control has the default value for a property.
+
+ The control to check.
+ The property to check.
+
+ True if the property has the default value; false otherwise.
+
+
+
+
+ Gets or sets a value indicating whether the Header property has been
+ set to the item of an ItemsControl.
+
+
+
+
+ Gets or sets the item that labels the control.
+
+
+ The item that labels the control. The default value is null.
+
+
+
+
+ Gets or sets a data template that is used to display the contents of
+ the control's header.
+
+
+ Gets or sets a data template that is used to display the contents of
+ the control's header. The default is null.
+
+
+
+
+ Gets or sets the that is
+ applied to the container element generated for each item.
+
+
+ The that is applied to the
+ container element generated for each item. The default is null.
+
+
+
+
+ Gets the ItemsControlHelper that is associated with this control.
+
+
+
+
+ Stores a value indicating whether this element has logical focus.
+
+
+
+
+ Identifies the Command dependency property.
+
+
+
+
+ Handles changes to the Command DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Handles changes to the Command property.
+
+ Old value.
+ New value.
+
+
+
+ Identifies the CommandParameter dependency property.
+
+
+
+
+ Handles changes to the CommandParameter DependencyProperty.
+
+ DependencyObject that changed.
+ Event data for the DependencyPropertyChangedEvent.
+
+
+
+ Handles changes to the CommandParameter property.
+
+
+
+
+ Initializes a new instance of the MenuItem class.
+
+
+
+
+ Called when the template's tree is generated.
+
+
+
+
+ Invoked whenever an unhandled GotFocus event reaches this element in its route.
+
+ A RoutedEventArgs that contains event data.
+
+
+
+ Raises the LostFocus routed event by using the event data that is provided.
+
+ A RoutedEventArgs that contains event data.
+
+
+
+ Called whenever the mouse enters a MenuItem.
+
+ The event data for the MouseEnter event.
+
+
+
+ Called whenever the mouse leaves a MenuItem.
+
+ The event data for the MouseLeave event.
+
+
+
+ Called when the left mouse button is released.
+
+ The event data for the MouseLeftButtonUp event.
+
+
+
+ Responds to the KeyDown event.
+
+ The event data for the KeyDown event.
+
+
+
+ Called when the Items property changes.
+
+ The event data for the ItemsChanged event.
+
+
+
+ Called when a MenuItem is clicked and raises a Click event.
+
+
+
+
+ Handles the CanExecuteChanged event of the Command property.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Updates the IsEnabled property.
+
+
+ WPF overrides the local value of IsEnabled according to ICommand, so Silverlight does, too.
+
+ True if ChangeVisualState should be called.
+
+
+
+ Called when the IsEnabled property changes.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Called when the Loaded event is raised.
+
+ Source of the event.
+ Event arguments.
+
+
+
+ Changes to the correct visual state(s) for the control.
+
+ True to use transitions; otherwise false.
+
+
+
+ Occurs when a MenuItem is clicked.
+
+
+
+
+ Gets or sets a reference to the MenuBase parent.
+
+
+
+
+ Gets or sets the command associated with the menu item.
+
+
+
+
+ Gets or sets the parameter to pass to the Command property of a MenuItem.
+
+
+
+
+ Control that is used to separate items in items controls.
+
+ Preview
+
+
+
+ Initializes a new instance of the Separator class.
+
+
+
+
+ Represents a that supports
+ objects,
+ such as .
+
+ Stable
+
+
+
+ The DataTemplate to apply to the ItemTemplate property on a
+ generated HeaderedItemsControl (such as a MenuItem or a
+ TreeViewItem), to indicate how to display items from the next level
+ in the data hierarchy.
+
+
+
+
+ The Style to apply to the ItemContainerStyle property on a generated
+ HeaderedItemsControl (such as a MenuItem or a TreeViewItem), to
+ indicate how to style items from the next level in the data
+ hierarchy.
+
+
+
+
+ Initializes a new instance of the
+ class.
+
+
+
+
+ Gets or sets the collection that is used to generate content for the
+ next sublevel in the data hierarchy.
+
+
+ The collection that is used to generate content for the next
+ sublevel in the data hierarchy. The default value is null.
+
+
+
+
+ Gets a value indicating whether the ItemTemplate property was set on
+ the template.
+
+
+
+
+ Gets or sets the to
+ apply to the
+
+ property on a generated
+ , such
+ as a , to
+ indicate how to display items from the next sublevel in the data
+ hierarchy.
+
+
+ The to apply to the
+
+ property on a generated
+ , such
+ as a , to
+ indicate how to display items from the next sublevel in the data
+ hierarchy.
+
+
+
+
+ Gets a value indicating whether the ItemContainerStyle property was
+ set on the template.
+
+
+
+
+ Gets or sets the that is
+ applied to the item container for each child item.
+
+
+ The style that is applied to the item container for each child item.
+
+
+
+
+ Represents a page used by the TimePicker control that allows the user to choose a time (hour/minute/am/pm).
+
+
+
+
+ Represents a base class for pages that work with DateTimePickerBase to allow users to choose a date/time.
+
+
+
+
+ Represents an interface for DatePicker/TimePicker to use for communicating with a picker page.
+
+
+
+
+ Gets or sets the DateTime to show in the picker page and to set when the user makes a selection.
+
+
+
+
+ Initializes the DateTimePickerPageBase class; must be called from the subclass's constructor.
+
+ Primary selector.
+ Secondary selector.
+ Tertiary selector.
+
+
+
+ Called when the Back key is pressed.
+
+ Event arguments.
+
+
+
+ Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
+
+ LoopingSelectors ordered by culture-specific priority.
+
+
+
+ Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
+
+ Culture-specific date/time format string.
+ Date/time format string characters for the primary/secondary/tertiary LoopingSelectors.
+ Instances for the primary/secondary/tertiary LoopingSelectors.
+ LoopingSelectors ordered by culture-specific priority.
+
+
+
+ Called when a page is no longer the active page in a frame.
+
+ An object that contains the event data.
+
+
+
+ Called when a page becomes the active page in a frame.
+
+ An object that contains the event data.
+
+
+
+ Gets or sets the DateTime to show in the picker page and to set when the user makes a selection.
+
+
+
+
+ Initializes a new instance of the TimePickerPage control.
+
+
+
+
+ Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
+
+ LoopingSelectors ordered by culture-specific priority.
+
+
+
+ Handles changes to the page's Orientation property.
+
+ Event arguments.
+
+
+
+ InitializeComponent
+
+
+
+
+ Defines how the LoopingSelector communicates with data source.
+
+
+
+
+ Get the next datum, relative to an existing datum.
+
+ The datum the return value will be relative to.
+ The next datum.
+
+
+
+ Get the previous datum, relative to an existing datum.
+
+ The datum the return value will be relative to.
+ The previous datum.
+
+
+
+ The selected item. Should never be null.
+
+
+
+
+ Raised when the selection changes.
+
+
+
+
+ Represents a control that allows the user to choose a date (day/month/year).
+
+
+
+
+ Represents a base class for controls that allow the user to choose a date/time.
+
+
+
+
+ Identifies the Value DependencyProperty.
+
+
+
+
+ Called when the value changes.
+
+ The event data.
+
+
+
+ Identifies the ValueString DependencyProperty.
+
+
+
+
+ Identifies the ValueStringFormat DependencyProperty.
+
+
+
+
+ Identifies the Header DependencyProperty.
+
+
+
+
+ Identifies the HeaderTemplate DependencyProperty.
+
+
+
+
+ Identifies the PickerPageUri DependencyProperty.
+
+
+
+
+ Initializes a new instance of the DateTimePickerBase control.
+
+
+
+
+ Called when the control's Template is expanded.
+
+
+
+
+ Event that is invoked when the Value property changes.
+
+
+
+
+ Gets or sets the DateTime value.
+
+
+
+
+ Gets the string representation of the selected value.
+
+
+
+
+ Gets or sets the format string to use when converting the Value property to a string.
+
+
+
+
+ Gets or sets the header of the control.
+
+
+
+
+ Gets or sets the template used to display the control's header.
+
+
+
+
+ Gets or sets the Uri to use for loading the IDateTimePickerPage instance when the control is clicked.
+
+
+
+
+ Initializes a new instance of the DatePicker control.
+
+
+
+
+ Represents a page used by the DatePicker control that allows the user to choose a date (day/month/year).
+
+
+
+
+ Initializes a new instance of the DatePickerPage control.
+
+
+
+
+ Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
+
+ LoopingSelectors ordered by culture-specific priority.
+
+
+
+ Handles changes to the page's Orientation property.
+
+ Event arguments.
+
+
+
+ InitializeComponent
+
+
+
+
+ Provides access to the localized resources used by the DatePicker and TimePicker.
+
+
+
+
+ Gets the localized DatePicker title string.
+
+
+
+
+ Gets the localized TimePicker title string.
+
+
+
+
+ Implements a wrapper for DateTime that provides formatted strings for DatePicker.
+
+
+
+
+ Initializes a new instance of the DateTimeWrapper class.
+
+ DateTime to wrap.
+
+
+
+ Returns a value indicating whether the current culture uses a 24-hour clock.
+
+ True if it uses a 24-hour clock; false otherwise.
+
+
+
+ Gets the DateTime being wrapped.
+
+
+
+
+ Gets the 4-digit year as a string.
+
+
+
+
+ Gets the 2-digit month as a string.
+
+
+
+
+ Gets the month name as a string.
+
+
+
+
+ Gets the 2-digit day as a string.
+
+
+
+
+ Gets the day name as a string.
+
+
+
+
+ Gets the hour as a string.
+
+
+
+
+ Gets the 2-digit minute as a string.
+
+
+
+
+ Gets the AM/PM designator as a string.
+
+
+
+
+ Provides data for the DatePicker and TimePicker's ValueChanged event.
+
+
+
+
+ Initializes a new instance of the DateTimeValueChangedEventArgs class.
+
+ Old DateTime value.
+ New DateTime value.
+
+
+
+ Gets or sets the old DateTime value.
+
+
+
+
+ Gets or sets the new DateTime value.
+
+
+
+
+ Represents a control that allows the user to choose a time (hour/minute/am/pm).
+
+
+
+
+ Initializes a new instance of the TimePicker control.
+
+
+
+
+ The GestureListener class raises events similar to those provided by the XNA TouchPanel, but it is designed for
+ Silverlight's event-driven model, rather than XNA's loop/polling model, and it also takes care of the hit testing
+ and event routing.
+
+
+
+
+ Handle touch events.
+
+
+
+
+
+
+ A touch has started.
+
+
+
+
+ A touch is continuing...
+
+
+
+
+ A touch has ended.
+
+
+
+
+ This method does all the necessary work to raise a gesture event. It sets the orginal source, does the routing,
+ handles Handled, and only creates the event args if they are needed.
+
+ This is the type of event args that will be raised.
+ Gets the specific event to raise.
+ Lazy creator function for the event args.
+ Indicates whether the mouse capture should be released
+
+
+
+ The Tap event (touch, release, no movement).
+
+
+
+
+ The DoubleTap event is raised instead of Tap if the time between two taps is short eonugh.
+
+
+
+
+ The Hold event (touch and hold for one second)
+
+
+
+
+ The DragStarted event.
+
+
+
+
+ The DragDelta event.
+
+
+
+
+ The DragCompleted event. Will be raised on touch release after a drag, or
+ when a second touch point is added.
+
+
+
+
+ The Flick event. Raised when a drag that was fast enough ends with a release.
+
+
+
+
+ The PinchStarted event.
+
+
+
+
+ Any two-touch point (two finger) operation.
+
+
+
+
+ The end of a pinch operation.
+
+
+
+
+ The base class for all gesture events. Also used by Tap, DoubleTap and Hold.
+
+
+
+
+ Returns the position of the gesture's starting point relative to a given UIElement.
+
+ The return value will be relative to this element.
+ The gesture's starting point relative to the given UIElement.
+
+
+
+ Returns the position of a given point relative to a given UIElement.
+
+ The return value will be relative to this element.
+ The point to translate.
+ The given point relative to the given UIElement.
+
+
+
+ The point, in unrotated screen coordinates, where the gesture occurred.
+
+
+
+
+ The first hit-testable item under the touch point. Determined by a combination of order in the tree and
+ Z-order.
+
+
+
+
+ If an event handler sets this to true, it stops event bubbling.
+
+
+
+
+ The event args used in the DragStarted event.
+
+
+
+
+ The direction of the drag gesture, as determined by the initial drag change.
+
+
+
+
+ The event args used by the DragDelta event.
+
+
+
+
+ The horizontal (X) change for this drag event.
+
+
+
+
+ The vertical (Y) change for this drag event.
+
+
+
+
+ The direction of the drag gesture, as determined by the initial drag change.
+
+
+
+
+ The event args used by the DragCompleted event.
+
+
+
+
+ The total horizontal (X) change of the drag event.
+
+
+
+
+ The total vertical (Y) change of the drag event.
+
+
+
+
+ The direction of the drag gesture, as determined by the initial drag change.
+
+
+
+
+ The final horizontal (X) velocity of the drag, if the drag was inertial.
+
+
+
+
+ The final vertical (Y) velocity of the drag, if the drag was inertial.
+
+
+
+
+ The event args used by the Flick event.
+
+
+
+
+ The horizontal (X) velocity of the flick.
+
+
+
+
+ The vertical (Y) velocity of the flick.
+
+
+
+
+ The angle of the flick.
+
+
+
+
+ The direction of the flick gesture, as determined by the flick velocities.
+
+
+
+
+ The base class for multi-touch gesture event args. Currently used only for
+ two-finger (pinch) operations.
+
+
+
+
+ Returns the position of either of the two touch points (0 or 1) relative to
+ the UIElement provided.
+
+ The return value will be relative to this element.
+ The touchpoint to use (0 or 1).
+ The gesture's starting point relative to the given UIElement.
+
+
+
+ The second touch point. The first is stored in GestureEventArgs.
+
+
+
+
+ The event args used by the PinchStarted event.
+
+
+
+
+ The distance between the two touch points.
+
+
+
+
+ The angle defined by the two touch points.
+
+
+
+
+ The event args used by the PinchDelta and PinchCompleted events.
+
+
+
+
+ Returns the ratio of the current distance between touchpoints / the original distance
+ between the touchpoints.
+
+
+
+
+ Returns the difference in angle between the current touch positions and the original
+ touch positions.
+
+
+
+
+ The GestureService class is the helper for getting and setting GestureListeners
+ on elements.
+
+
+
+
+ Gets a GestureListener for the new element. Will create a new one if necessary.
+
+ The object to get the GestureListener from.
+ Either the previously existing GestureListener, or a new one.
+
+
+
+ Gets the GestureListener on an element. If one is not set, can create a new one
+ so that this will never return null, depending on the state of the createIfMissing
+ flag.
+
+ The object to get the GestureListener from.
+ When this is true, if the attached property was not set on the element, it will create one and set it on the element.
+
+
+
+
+ Sets the GestureListener on an element. Needed for XAML, but should not be used in code. Use
+ GetGestureListener instead, which will create a new instance if one is not already set, to
+ add your handlers to an element.
+
+ The object to set the GestureListener on.
+ The GestureListener.
+
+
+
+ This is used to set the value of the attached DependencyProperty internally.
+
+ The object to set the GestureListener on.
+ The GestureListener.
+
+
+
+ The definition of the GestureListener attached DependencyProperty.
+
+
+
+
+ An infinitely scrolling, UI- and data-virtualizing selection control.
+
+
+
+
+ The DataSource DependencyProperty
+
+
+
+
+ The ItemTemplate DependencyProperty
+
+
+
+
+ Creates a new LoopingSelector.
+
+
+
+
+ The IsExpanded DependencyProperty.
+
+
+
+
+ When overridden in a derived class, is invoked whenever application code or internal processes (such as a rebuilding layout pass) call .
+ In simplest terms, this means the method is called just before a UI element displays in an application.
+ For more information, see Remarks.
+
+
+
+
+ Balances the items.
+
+
+
+
+ The data source that the this control is the view for.
+
+
+
+
+ The ItemTemplate property
+
+
+
+
+ The size of the items, excluding the ItemMargin.
+
+
+
+
+ The margin around the items, to be a part of the touchable area.
+
+
+
+
+ The IsExpanded property controls the expanded state of this control.
+
+
+
+
+ The IsExpandedChanged event will be raised whenever the IsExpanded state changes.
+
+
+
+
+ The items that will be contained in the LoopingSelector.
+
+
+
+
+ Create a new LoopingSelectorItem.
+
+
+
+
+ Put this item into a new state.
+
+ The new state.
+ Flag indicating that transitions should be used when going to the new state.
+
+
+
+ Returns the current state.
+
+ The current state.
+
+
+
+ Override of OnApplyTemplate
+
+
+
+
+ The Click event. This is needed because there is no gesture for touch-down, pause
+ longer than the Hold time, and touch-up. Tap will not be raise, and Hold is not
+ adequate.
+
+
+
+
+ The states that this can be in.
+
+
+
+
+ Not visible
+
+
+
+
+ Visible
+
+
+
+
+ Selected
+
+
+
+
+ Represents a switch that can be toggled between two states.
+
+
+
+
+ Common visual states.
+
+
+
+
+ Normal visual state.
+
+
+
+
+ Disabled visual state.
+
+
+
+
+ Check visual states.
+
+
+
+
+ Checked visual state.
+
+
+
+
+ Dragging visual state.
+
+
+
+
+ Unchecked visual state.
+
+
+
+
+ Switch root template part name.
+
+
+
+
+ Switch background template part name.
+
+
+
+
+ Switch track template part name.
+
+
+
+
+ Switch thumb template part name.
+
+
+
+
+ The minimum translation.
+
+
+
+
+ Identifies the SwitchForeground dependency property.
+
+
+
+
+ The background TranslateTransform.
+
+
+
+
+ The thumb TranslateTransform.
+
+
+
+
+ The root template part.
+
+
+
+
+ The track template part.
+
+
+
+
+ The thumb template part.
+
+
+
+
+ The maximum translation.
+
+
+
+
+ The drag translation.
+
+
+
+
+ Whether the translation ever changed during the drag.
+
+
+
+
+ Whether the dragging state is current.
+
+
+
+
+ Initializes a new instance of the ToggleSwitch class.
+
+
+
+
+ Change the visual state.
+
+ Indicates whether to use animation transitions.
+
+
+
+ Called by the OnClick method to implement toggle behavior.
+
+
+
+
+ Gets all the template parts and initializes the corresponding state.
+
+
+
+
+ Handles started drags on the root.
+
+ The event sender.
+ The event information.
+
+
+
+ Handles drags on the root.
+
+ The event sender.
+ The event information.
+
+
+
+ Handles completed drags on the root.
+
+ The event sender.
+ The event information.
+
+
+
+ Handles changed sizes for the track and the thumb.
+ Sets the clip of the track and computes the indeterminate and checked translations.
+
+ The event sender.
+ The event information.
+
+
+
+ Gets or sets the switch foreground.
+
+
+
+
+ Gets and sets the thumb and background translation.
+
+ The translation.
+
+
+
+ Converts bool? values to "Off" and "On" strings.
+
+
+
+
+ Converts a value.
+
+ The value produced by the binding source.
+ The type of the binding target property.
+ The converter parameter to use.
+ The culture to use in the converter.
+ A converted value. If the method returns null, the valid null value is used.
+
+
+
+ Converts a value.
+
+ The value produced by the binding source.
+ The type of the binding target property.
+ The converter parameter to use.
+ The culture to use in the converter.
+ A converted value. If the method returns null, the valid null value is used.
+
+
+
+ Represents a switch that can be toggled between two states.
+
+
+
+
+ Common visual states.
+
+
+
+
+ Normal visual state.
+
+
+
+
+ Disabled visual state.
+
+
+
+
+ The ToggleButton that drives this.
+
+
+
+
+ Identifies the Header dependency property.
+
+
+
+
+ Identifies the HeaderTemplate dependency property.
+
+
+
+
+ The IsChecked DependencyProperty definition.
+
+
+
+
+ The Switch part.
+
+
+
+
+ Whether the content was set.
+
+
+
+
+ Initializes a new instance of the ToggleSwitch class.
+
+
+
+
+ Makes the content an "Off" or "On" string to match the state.
+
+
+
+
+ Change the visual state.
+
+ Indicates whether to use animation transitions.
+
+
+
+ Makes the content an "Off" or "On" string to match the state if the content is set to null in the design tool.
+
+ The old content.
+ The new content.
+
+
+
+ Gets all the template parts and initializes the corresponding state.
+
+
+
+
+ Handles the loading of this control.
+ Sets the content if it is null when the control is loaded.
+
+ The event sender.
+ The event information.
+
+
+
+ Checks the state when the toggle switch is checked and simulates the event.
+
+ The event sender.
+ The event information.
+
+
+
+ Unchecks the state when the toggle switch is unchecked and simulates the event.
+
+ The event sender.
+ The event information.
+
+
+
+ Gets or sets the header.
+
+
+
+
+ Gets or sets the header template.
+
+
+
+
+ Gets and sets the IsChecked property.
+
+
+
+
+ The Checked event handler. Will be raised when the switch is checked.
+
+
+
+
+ The Unchecked event handler. Will be raised when the switch is unchecked.
+
+
+
+
+ Gets or sets the toggle switch.
+
+
+
+
+ A strongly-typed resource class, for looking up localized strings, etc.
+
+
+
+
+ Returns the cached ResourceManager instance used by this class.
+
+
+
+
+ Overrides the current thread's CurrentUICulture property for all
+ resource lookups using this strongly typed resource class.
+
+
+
+
+ Looks up a localized string similar to CHOOSE DATE.
+
+
+
+
+ Looks up a localized string similar to cancel.
+
+
+
+
+ Looks up a localized string similar to done.
+
+
+
+
+ Looks up a localized string similar to Off.
+
+
+
+
+ Looks up a localized string similar to On.
+
+
+
+
+ Looks up a localized string similar to CHOOSE TIME.
+
+
+
+
+ Looks up a localized string similar to '{0}' is unable to convert '{1}' to '{2}'..
+
+
+
+
+ Looks up a localized string similar to '{0}' cannot convert from '{1}'..
+
+
+
+
+ Looks up a localized string similar to The type was unexpected..
+
+
+
+
+ Looks up a localized string similar to Invalid length value '{0}'..
+
+
+
+
+ Looks up a localized string similar to Invalid Orientation value '{0}'..
+
+
+
+
+ The OrientedSize structure is used to abstract the growth direction from
+ the layout algorithms of WrapPanel. When the growth direction is
+ oriented horizontally (ex: the next element is arranged on the side of
+ the previous element), then the Width grows directly with the placement
+ of elements and Height grows indirectly with the size of the largest
+ element in the row. When the orientation is reversed, so is the
+ directional growth with respect to Width and Height.
+
+
+
+
+ The orientation of the structure.
+
+
+
+
+ The size dimension that grows directly with layout placement.
+
+
+
+
+ The size dimension that grows indirectly with the maximum value of
+ the layout row or column.
+
+
+
+
+ Initializes a new OrientedSize structure.
+
+ Orientation of the structure.
+
+
+
+ Initializes a new OrientedSize structure.
+
+ Orientation of the structure.
+ Un-oriented width of the structure.
+ Un-oriented height of the structure.
+
+
+
+ Gets the orientation of the structure.
+
+
+
+
+ Gets or sets the size dimension that grows directly with layout
+ placement.
+
+
+
+
+ Gets or sets the size dimension that grows indirectly with the
+ maximum value of the layout row or column.
+
+
+
+
+ Gets or sets the width of the size.
+
+
+
+
+ Gets or sets the height of the size.
+
+
+
+
+ Positions child elements sequentially from left to right or top to
+ bottom. When elements extend beyond the panel edge, elements are
+ positioned in the next row or column.
+
+ Stable
+
+
+
+ A value indicating whether a dependency property change handler
+ should ignore the next change notification. This is used to reset
+ the value of properties without performing any of the actions in
+ their change handlers.
+
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property
+
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property.
+
+
+
+
+ Identifies the
+
+ dependency property.
+
+
+ The identifier for the
+
+ dependency property.
+
+
+
+
+ OrientationProperty property changed handler.
+
+ WrapPanel that changed its Orientation.
+ Event arguments.
+
+
+
+ Initializes a new instance of the
+ class.
+
+
+
+
+ Property changed handler for ItemHeight and ItemWidth.
+
+
+ WrapPanel that changed its ItemHeight or ItemWidth.
+
+ Event arguments.
+
+
+
+ Measures the child elements of a
+ in anticipation
+ of arranging them during the
+
+ pass.
+
+
+ The size available to child elements of the wrap panel.
+
+
+ The size required by the
+ and its
+ elements.
+
+
+
+
+ Arranges and sizes the
+ control and its
+ child elements.
+
+
+ The area within the parent that the
+ should use
+ arrange itself and its children.
+
+
+ The actual size used by the
+ .
+
+
+
+
+ Arrange a sequence of elements in a single line.
+
+
+ Index of the first element in the sequence to arrange.
+
+
+ Index of the last element in the sequence to arrange.
+
+
+ Optional fixed growth in the primary direction.
+
+
+ Offset of the line in the indirect direction.
+
+
+ Shared indirect growth of the elements on this line.
+
+
+
+
+ Gets or sets the height of the layout area for each item that is
+ contained in a .
+
+
+ The height applied to the layout area of each item that is contained
+ within a . The
+ default value is .
+
+
+
+
+ Gets or sets the width of the layout area for each item that is
+ contained in a .
+
+
+ The width that applies to the layout area of each item that is
+ contained in a .
+ The default value is .
+
+
+
+
+ Gets or sets the direction in which child elements are arranged.
+
+
+ One of the
+ values. The default is
+ .
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.dll b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.dll
new file mode 100644
index 0000000..0419e95
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.dll differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.xml b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.xml
new file mode 100644
index 0000000..c50e371
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/Libraries/WPF_Interactivity/System.Windows.Interactivity.xml
@@ -0,0 +1,1072 @@
+
+
+
+ System.Windows.Interactivity
+
+
+
+
+ Represents a collection of IAttachedObject with a shared AssociatedObject and provides change notifications to its contents when that AssociatedObject changes.
+
+
+
+
+ An interface for an object that can be attached to another object.
+
+
+
+
+ Attaches to the specified object.
+
+ The object to attach to.
+
+
+
+ Detaches this instance from its associated object.
+
+
+
+
+ Gets the associated object.
+
+ The associated object.
+ Represents the object the instance is attached to.
+
+
+
+ Initializes a new instance of the class.
+
+ Internal, because this should not be inherited outside this assembly.
+
+
+
+ Called immediately after the collection is attached to an AssociatedObject.
+
+
+
+
+ Called when the collection is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Called when a new item is added to the collection.
+
+ The new item.
+
+
+
+ Called when an item is removed from the collection.
+
+ The removed item.
+
+
+ Cannot add the instance to a collection more than once.
+
+
+
+ Attaches to the specified object.
+
+ The object to attach to.
+ The IAttachedObject is already attached to a different object.
+
+
+
+ Detaches this instance from its associated object.
+
+
+
+
+ The object on which the collection is hosted.
+
+
+
+
+ Gets the associated object.
+
+ The associated object.
+
+
+
+ Encapsulates state information and zero or more ICommands into an attachable object.
+
+ The type the can be attached to.
+
+ Behavior is the base class for providing attachable state and commands to an object.
+ The types the Behavior can be attached to can be controlled by the generic parameter.
+ Override OnAttached() and OnDetaching() methods to hook and unhook any necessary handlers
+ from the AssociatedObject.
+
+
+
+
+ Encapsulates state information and zero or more ICommands into an attachable object.
+
+ This is an infrastructure class. Behavior authors should derive from Behavior<T> instead of from this class.
+
+
+
+ Called after the behavior is attached to an AssociatedObject.
+
+ Override this to hook up functionality to the AssociatedObject.
+
+
+
+ Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
+
+ Override this to unhook functionality from the AssociatedObject.
+
+
+
+ Attaches to the specified object.
+
+ The object to attach to.
+ The Behavior is already hosted on a different element.
+ dependencyObject does not satisfy the Behavior type constraint.
+
+
+
+ Detaches this instance from its associated object.
+
+
+
+
+ The type to which this behavior can be attached.
+
+
+
+
+ Gets the object to which this behavior is attached.
+
+
+
+
+ Gets the associated object.
+
+ The associated object.
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Gets the object to which this is attached.
+
+
+
+
+ Represents a collection of behaviors with a shared AssociatedObject and provides change notifications to its contents when that AssociatedObject changes.
+
+
+
+
+ Initializes a new instance of the class.
+
+ Internal, because this should not be inherited outside this assembly.
+
+
+
+ Called immediately after the collection is attached to an AssociatedObject.
+
+
+
+
+ Called when the collection is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Called when a new item is added to the collection.
+
+ The new item.
+
+
+
+ Called when an item is removed from the collection.
+
+ The removed item.
+
+
+
+ Creates a new instance of the BehaviorCollection.
+
+ The new instance.
+
+
+
+ Enumerates possible values for reusable property value editors.
+
+
+
+
+ Uses the element picker, if supported, to edit this property at design time.
+
+
+
+
+ Uses the storyboard picker, if supported, to edit this property at design time.
+
+
+
+
+ Uses the state picker, if supported, to edit this property at design time.
+
+
+
+
+ Uses the element-binding picker, if supported, to edit this property at design time.
+
+
+
+
+ Uses the property-binding picker, if supported, to edit this property at design time.
+
+
+
+
+ Associates the given editor type with the property on which the CustomPropertyValueEditor is applied.
+
+ Use this attribute to get improved design-time editing for properties that denote element (by name), storyboards, or states (by name).
+
+
+
+ Initializes a new instance of the class.
+
+ The custom property value editor.
+
+
+
+ Gets or sets the custom property value editor.
+
+ The custom property value editor.
+
+
+
+ Provides design tools information about what to instantiate for a given action or command.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The type this attribute applies to.
+ The type of to instantiate.
+ A single argument for the specified .
+ is not derived from TriggerBase.
+ This constructor is useful if the specifed has a single argument. The
+ resulting code will be CLS compliant.
+
+
+
+ Initializes a new instance of the class.
+
+ The type this attribute applies to.
+ The type of to instantiate.
+ The constructor arguments for the specified .
+ is not derived from TriggerBase.
+
+
+
+ Instantiates this instance.
+
+ The specified by the DefaultTriggerAttribute.
+
+
+
+ Gets the type that this DefaultTriggerAttribute applies to.
+
+ The type this DefaultTriggerAttribute applies to.
+
+
+
+ Gets the type of the to instantiate.
+
+ The type of the to instantiate.
+
+
+
+ Gets the parameters to pass to the constructor.
+
+ The parameters to pass to the constructor.
+
+
+
+ This method will use the VisualTreeHelper.GetParent method to do a depth first walk up
+ the visual tree and return all ancestors of the specified object, including the object itself.
+
+ The object in the visual tree to find ancestors of.
+ Returns itself an all ancestors in the visual tree.
+
+
+
+ EventObserver is designed to help manage event handlers by detatching when disposed. Creating this object will also attach in the constructor.
+
+
+
+
+ Creates an instance of EventObserver and attaches to the supplied event on the supplied target. Call dispose to detach.
+
+ The event to attach and detach from.
+ The target object the event is defined on. Null if the method is static.
+ The delegate to attach to the event.
+
+
+
+ Detaches the handler from the event.
+
+
+
+
+ A trigger that listens for a specified event on its source and fires when that event is fired.
+
+
+
+
+ Represents a trigger that can listen to an element other than its AssociatedObject.
+
+ The type that this trigger can be associated with.
+
+ EventTriggerBase extends TriggerBase to add knowledge of another object than the one it is attached to.
+ This allows a user to attach a Trigger/Action pair to one element and invoke the Action in response to a
+ change in another object somewhere else. Override OnSourceChanged to hook or unhook handlers on the source
+ element, and OnAttached/OnDetaching for the associated element. The type of the Source element can be
+ constrained by the generic type parameter. If you need control over the type of the
+ AssociatedObject, set a TypeConstraintAttribute on your derived type.
+
+
+
+
+ Represents a trigger that can listen to an object other than its AssociatedObject.
+
+ This is an infrastructure class. Trigger authors should derive from EventTriggerBase<T> instead of this class.
+
+
+
+ Represents an object that can invoke Actions conditionally.
+
+ This is an infrastructure class. Trigger authors should derive from Trigger<T> instead of this class.
+
+
+
+ Invoke all actions associated with this trigger.
+
+ Derived classes should call this to fire the trigger.
+
+
+
+ Called after the trigger is attached to an AssociatedObject.
+
+
+
+
+ Called when the trigger is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Creates a new instance of the TriggerBase derived class.
+
+ The new instance.
+
+
+
+ Attaches to the specified object.
+
+ The object to attach to.
+ Cannot host the same trigger on more than one object at a time.
+ dependencyObject does not satisfy the trigger type constraint.
+
+
+
+ Detaches this instance from its associated object.
+
+
+
+
+ Gets the object to which the trigger is attached.
+
+ The associated object.
+
+
+
+ Gets the type constraint of the associated object.
+
+ The associated object type constraint.
+
+
+
+ Gets the actions associated with this trigger.
+
+ The actions associated with this trigger.
+
+
+
+ Event handler for registering to PreviewInvoke.
+
+
+
+
+ Gets the associated object.
+
+ The associated object.
+
+
+
+ Specifies the name of the Event this EventTriggerBase is listening for.
+
+
+
+
+
+ Called when the event associated with this EventTriggerBase is fired. By default, this will invoke all actions on the trigger.
+
+ The instance containing the event data.
+ Override this to provide more granular control over when actions associated with this trigger will be invoked.
+
+
+
+ Called when the source changes.
+
+ The old source.
+ The new source.
+ This function should be overridden in derived classes to hook functionality to and unhook functionality from the changing source objects.
+
+
+
+ Called after the trigger is attached to an AssociatedObject.
+
+
+
+
+ Called when the trigger is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+ Could not find eventName on the Target.
+
+
+
+ Gets the type constraint of the associated object.
+
+ The associated object type constraint.
+ Define a TypeConstraintAttribute on a derived type to constrain the types it may be attached to.
+
+
+
+ Gets the source type constraint.
+
+ The source type constraint.
+
+
+
+ Gets or sets the target object. If TargetObject is not set, the target will look for the object specified by TargetName. If an element referred to by TargetName cannot be found, the target will default to the AssociatedObject. This is a dependency property.
+
+ The target object.
+
+
+
+ Gets or sets the name of the element this EventTriggerBase listens for as a source. If the name is not set or cannot be resolved, the AssociatedObject will be used. This is a dependency property.
+
+ The name of the source element.
+
+
+
+ Gets the resolved source. If is not set or cannot be resolved, defaults to AssociatedObject.
+
+ The resolved source object.
+ In general, this property should be used in place of AssociatedObject in derived classes.
+ The element pointed to by does not satisify the type constraint.
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Called when the source property changes.
+
+ Override this to hook functionality to and unhook functionality from the specified source, rather than the AssociatedObject.
+ The old source.
+ The new source.
+
+
+
+ Gets the resolved source. If is not set or cannot be resolved, defaults to AssociatedObject.
+
+ The resolved source object.
+ In general, this property should be used in place of AssociatedObject in derived classes.
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Initializes a new instance of the class.
+
+ Name of the event.
+
+
+
+ Gets or sets the name of the event to listen for. This is a dependency property.
+
+ The name of the event.
+
+
+
+ Static class that owns the Triggers and Behaviors attached properties. Handles propagation of AssociatedObject change notifications.
+
+
+
+
+ This property is used as the internal backing store for the public Triggers attached property.
+
+
+ This property is not exposed publicly. This forces clients to use the GetTriggers and SetTriggers methods to access the
+ collection, ensuring the collection exists and is set before it is used.
+
+
+
+
+ This property is used as the internal backing store for the public Behaviors attached property.
+
+
+ This property is not exposed publicly. This forces clients to use the GetBehaviors and SetBehaviors methods to access the
+ collection, ensuring the collection exists and is set before it is used.
+
+
+
+
+ Gets the TriggerCollection containing the triggers associated with the specified object.
+
+ The object from which to retrieve the triggers.
+ A TriggerCollection containing the triggers associated with the specified object.
+
+
+
+ Gets the associated with a specified object.
+
+ The object from which to retrieve the .
+ A containing the behaviors associated with the specified object.
+
+
+ Cannot host the same BehaviorCollection on more than one object at a time.
+
+
+ Cannot host the same TriggerCollection on more than one object at a time.
+
+
+
+ A helper function to take the place of FrameworkElement.IsLoaded, as this property is not available in Silverlight.
+
+ The element of interest.
+ True if the element has been loaded; otherwise, False.
+
+
+
+ Gets or sets a value indicating whether to run as if in design mode.
+
+
+ True if [should run in design mode]; otherwise, False.
+
+ Not to be used outside unit tests.
+
+
+
+ Executes a specified ICommand when invoked.
+
+
+
+
+ Represents an attachable object that encapsulates a unit of functionality.
+
+ The type to which this action can be attached.
+
+
+
+ Represents an attachable object that encapsulates a unit of functionality.
+
+ This is an infrastructure class. Action authors should derive from TriggerAction<T> instead of this class.
+
+
+
+ Attempts to invoke the action.
+
+ The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.
+
+
+
+ Invokes the action.
+
+ The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.
+
+
+
+ Called after the action is attached to an AssociatedObject.
+
+
+
+
+ Called when the action is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ When implemented in a derived class, creates a new instance of the derived class.
+
+ The new instance.
+
+
+
+ Attaches to the specified object.
+
+ The object to attach to.
+ Cannot host the same TriggerAction on more than one object at a time.
+ dependencyObject does not satisfy the TriggerAction type constraint.
+
+
+
+ Detaches this instance from its associated object.
+
+
+
+
+ Gets or sets a value indicating whether this action will run when invoked. This is a dependency property.
+
+
+ True if this action will be run when invoked; otherwise, False.
+
+
+
+
+ Gets the object to which this action is attached.
+
+ The associated object.
+
+
+
+ Gets the associated object type constraint.
+
+ The associated object type constraint.
+
+
+
+ Gets or sets a value indicating whether this instance is attached.
+
+ True if this instance is attached; otherwise, False.
+
+
+
+ Gets the associated object.
+
+ The associated object.
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Gets the object to which this is attached.
+
+ The associated object.
+
+
+
+ Gets the associated object type constraint.
+
+ The associated object type constraint.
+
+
+
+ Invokes the action.
+
+ The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.
+
+
+
+ Gets or sets the name of the command this action should invoke.
+
+ The name of the command this action should invoke.
+ This property will be superseded by the Command property if both are set.
+
+
+
+ Gets or sets the command this action should invoke. This is a dependency property.
+
+ The command to execute.
+ This property will take precedence over the CommandName property if both are set.
+
+
+
+ Gets or sets the command parameter. This is a dependency property.
+
+ The command parameter.
+ This is the value passed to ICommand.CanExecute and ICommand.Execute.
+
+
+
+ Provides data about which objects were affected when resolving a name change.
+
+
+
+
+ Helper class to handle the logic of resolving a TargetName into a Target element
+ based on the context provided by a host element.
+
+
+
+
+ Attempts to update the resolved object from the name within the context of the namescope reference element.
+
+ The old resolved object.
+
+ Resets the existing target and attempts to resolve the current TargetName from the
+ context of the current Host. If it cannot resolve from the context of the Host, it will
+ continue up the visual tree until it resolves. If it has not resolved it when it reaches
+ the root, it will set the Target to null and write a warning message to Debug output.
+
+
+
+
+ Occurs when the resolved element has changed.
+
+
+
+
+ Gets or sets the name of the element to attempt to resolve.
+
+ The name to attempt to resolve.
+
+
+
+ The resolved object. Will return the reference element if TargetName is null or empty, or if a resolve has not been attempted.
+
+
+
+
+ Gets or sets the reference element from which to perform the name resolution.
+
+ The reference element.
+
+
+
+ Gets or sets a value indicating whether the reference element load is pending.
+
+
+ True if [pending reference element load]; otherwise, False.
+
+
+ If the Host has not been loaded, the name will not be resolved.
+ In that case, delay the resolution and track that fact with this property.
+
+
+
+
+ Represents an action that can be targeted to affect an object other than its AssociatedObject.
+
+ The type constraint on the target.
+
+ TargetedTriggerAction extends TriggerAction to add knowledge of another element than the one it is attached to.
+ This allows a user to invoke the action on an element other than the one it is attached to in response to a
+ trigger firing. Override OnTargetChanged to hook or unhook handlers on the target element, and OnAttached/OnDetaching
+ for the associated element. The type of the Target element can be constrained by the generic type parameter. If
+ you need control over the type of the AssociatedObject, set a TypeConstraintAttribute on your derived type.
+
+
+
+
+ Represents an action that can be targeted to affect an object other than its AssociatedObject.
+
+ This is an infrastructure class. Action authors should derive from TargetedTriggerAction<T> instead of this class.
+
+
+
+ Called when the target changes.
+
+ The old target.
+ The new target.
+ This function should be overriden in derived classes to hook and unhook functionality from the changing source objects.
+
+
+
+ Called after the action is attached to an AssociatedObject.
+
+
+
+
+ Called when the action is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Gets or sets the target object. If TargetObject is not set, the target will look for the object specified by TargetName. If an element referred to by TargetName cannot be found, the target will default to the AssociatedObject. This is a dependency property.
+
+ The target object.
+
+
+
+ Gets or sets the name of the object this action targets. If Target is set, this property is ignored. If Target is not set and TargetName is not set or cannot be resolved, the target will default to the AssociatedObject. This is a dependency property.
+
+ The name of the target object.
+
+
+
+ Gets the target object. If TargetObject is set, returns TargetObject. Else, if TargetName is not set or cannot be resolved, defaults to the AssociatedObject.
+
+ The target object.
+ In general, this property should be used in place of AssociatedObject in derived classes.
+ The Target element does not satisfy the type constraint.
+
+
+
+ Gets the associated object type constraint.
+
+ The associated object type constraint.
+ Define a TypeConstraintAttribute on a derived type to constrain the types it may be attached to.
+
+
+
+ Gets the target type constraint.
+
+ The target type constraint.
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Called when the target property changes.
+
+ Override this to hook and unhook functionality on the specified Target, rather than the AssociatedObject.
+ The old target.
+ The new target.
+
+
+
+ Gets the target object. If TargetName is not set or cannot be resolved, defaults to the AssociatedObject.
+
+ The target.
+ In general, this property should be used in place of AssociatedObject in derived classes.
+
+
+
+ Represents a collection of actions with a shared AssociatedObject and provides change notifications to its contents when that AssociatedObject changes.
+
+
+
+
+ Initializes a new instance of the class.
+
+ Internal, because this should not be inherited outside this assembly.
+
+
+
+ Called immediately after the collection is attached to an AssociatedObject.
+
+
+
+
+ Called when the collection is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Called when a new item is added to the collection.
+
+ The new item.
+
+
+
+ Called when an item is removed from the collection.
+
+ The removed item.
+
+
+
+ Creates a new instance of the TriggerActionCollection.
+
+ The new instance.
+
+
+
+ Represents an object that can invoke actions conditionally.
+
+ The type to which this trigger can be attached.
+
+ TriggerBase is the base class for controlling actions. Override OnAttached() and
+ OnDetaching() to hook and unhook handlers on the AssociatedObject. You may
+ constrain the types that a derived TriggerBase may be attached to by specifying
+ the generic parameter. Call InvokeActions() to fire all Actions associated with
+ this TriggerBase.
+
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Gets the object to which the trigger is attached.
+
+ The associated object.
+
+
+
+ Gets the type constraint of the associated object.
+
+ The associated object type constraint.
+
+
+
+ Argument passed to PreviewInvoke event. Assigning Cancelling to True will cancel the invoking of the trigger.
+
+ This is an infrastructure class. Behavior attached to a trigger base object can add its behavior as a listener to TriggerBase.PreviewInvoke.
+
+
+
+ Represents a collection of triggers with a shared AssociatedObject and provides change notifications to its contents when that AssociatedObject changes.
+
+
+
+
+ Initializes a new instance of the class.
+
+ Internal, because this should not be inherited outside this assembly.
+
+
+
+ Called immediately after the collection is attached to an AssociatedObject.
+
+
+
+
+ Called when the collection is being detached from its AssociatedObject, but before it has actually occurred.
+
+
+
+
+ Called when a new item is added to the collection.
+
+ The new item.
+
+
+
+ Called when an item is removed from the collection.
+
+ The removed item.
+
+
+
+ Creates a new instance of the .
+
+ The new instance.
+
+
+
+ Specifies type constraints on the AssociatedObject of TargetedTriggerAction and EventTriggerBase.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The constraint type.
+
+
+
+ Gets the constraint type.
+
+ The constraint type.
+
+
+
+ A strongly-typed resource class, for looking up localized strings, etc.
+
+
+
+
+ Returns the cached ResourceManager instance used by this class.
+
+
+
+
+ Overrides the current thread's CurrentUICulture property for all
+ resource lookups using this strongly typed resource class.
+
+
+
+
+ Looks up a localized string similar to Cannot set the same BehaviorCollection on multiple objects..
+
+
+
+
+ Looks up a localized string similar to An instance of a Behavior cannot be attached to more than one object at a time..
+
+
+
+
+ Looks up a localized string similar to Cannot host an instance of a TriggerAction in multiple TriggerCollections simultaneously. Remove it from one TriggerCollection before adding it to another..
+
+
+
+
+ Looks up a localized string similar to Cannot set the same TriggerCollection on multiple objects..
+
+
+
+
+ Looks up a localized string similar to An instance of a trigger cannot be attached to more than one object at a time..
+
+
+
+
+ Looks up a localized string similar to The command "{0}" does not exist or is not publicly exposed on {1}..
+
+
+
+
+ Looks up a localized string similar to "{0}" is not a valid type for the TriggerType parameter. Make sure "{0}" derives from TriggerBase..
+
+
+
+
+ Looks up a localized string similar to Cannot add the same instance of "{0}" to a "{1}" more than once..
+
+
+
+
+ Looks up a localized string similar to The event "{0}" on type "{1}" has an incompatible signature. Make sure the event is public and satisfies the EventHandler delegate..
+
+
+
+
+ Looks up a localized string similar to Cannot find an event named "{0}" on type "{1}"..
+
+
+
+
+ Looks up a localized string similar to An object of type "{0}" cannot have a {3} property of type "{1}". Instances of type "{0}" can have only a {3} property of type "{2}"..
+
+
+
+
+ Looks up a localized string similar to Cannot attach type "{0}" to type "{1}". Instances of type "{0}" can only be attached to objects of type "{2}"..
+
+
+
+
+ Looks up a localized string similar to Unable to resolve TargetName "{0}"..
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml
new file mode 100644
index 0000000..24ea7c7
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml.cs
new file mode 100644
index 0000000..62550e1
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/App.xaml.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public partial class App : Application
+ {
+ internal const string ServerAddress = "http://localhost:8000";
+
+ ///
+ /// Provides easy access to the root frame of the Phone Application.
+ ///
+ /// The root frame of the Phone Application.
+ public PhoneApplicationFrame RootFrame { get; private set; }
+
+ ///
+ /// Constructor for the Application object.
+ ///
+ public App()
+ {
+ // Global handler for uncaught exceptions.
+ UnhandledException += Application_UnhandledException;
+
+ // Show graphics profiling information while debugging.
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // Display the current frame rate counters.
+ Application.Current.Host.Settings.EnableFrameRateCounter = true;
+
+ // Show the areas of the app that are being redrawn in each frame.
+ //Application.Current.Host.Settings.EnableRedrawRegions = true;
+
+ // Enable non-production analysis visualization mode,
+ // which shows areas of a page that are being GPU accelerated with a colored overlay.
+ //Application.Current.Host.Settings.EnableCacheVisualization = true;
+ }
+
+ // Standard Silverlight initialization
+ InitializeComponent();
+
+ // Phone-specific initialization
+ InitializePhoneApplication();
+ }
+
+ // Code to execute when the application is launching (eg, from Start)
+ // This code will not execute when the application is reactivated
+ private void Application_Launching(object sender, LaunchingEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is activated (brought to foreground)
+ // This code will not execute when the application is first launched
+ private void Application_Activated(object sender, ActivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is deactivated (sent to background)
+ // This code will not execute when the application is closing
+ private void Application_Deactivated(object sender, DeactivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is closing (eg, user hit Back)
+ // This code will not execute when the application is deactivated
+ private void Application_Closing(object sender, ClosingEventArgs e)
+ {
+ }
+
+ // Code to execute if a navigation fails
+ private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // A navigation has failed; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ // Code to execute on Unhandled Exceptions
+ private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // An unhandled exception has occurred; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ #region Phone application initialization
+
+ // Avoid double-initialization
+ private bool phoneApplicationInitialized = false;
+
+ // Do not add any additional code to this method
+ private void InitializePhoneApplication()
+ {
+ if (phoneApplicationInitialized)
+ return;
+
+ // Create the frame but don't set it as RootVisual yet; this allows the splash
+ // screen to remain active until the application is ready to render.
+ RootFrame = new PhoneApplicationFrame();
+ RootFrame.Navigated += CompleteInitializePhoneApplication;
+
+ // Handle navigation failures
+ RootFrame.NavigationFailed += RootFrame_NavigationFailed;
+
+ // Ensure we don't initialize again
+ phoneApplicationInitialized = true;
+ }
+
+ // Do not add any additional code to this method
+ private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
+ {
+ // Set the root visual to allow the application to render
+ if (RootVisual != RootFrame)
+ RootVisual = RootFrame;
+
+ // Remove this handler since it is no longer needed
+ RootFrame.Navigated -= CompleteInitializePhoneApplication;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ApplicationIcon.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ApplicationIcon.png
new file mode 100644
index 0000000..5859393
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ApplicationIcon.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Background.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Background.png
new file mode 100644
index 0000000..e46f21d
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Background.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml
new file mode 100644
index 0000000..7045771
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml.cs
new file mode 100644
index 0000000..3b78b4e
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/NotificationBox.xaml.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+using System.Windows.Controls.Primitives;
+using Microsoft.Phone.Controls;
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ public partial class NotificationBox : UserControl
+ {
+ #region Fields
+
+ private readonly IsolatedStorageSettings Settings = IsolatedStorageSettings.ApplicationSettings;
+ private static Popup _popup;
+
+ #endregion
+
+ public string Title { get; set; }
+ public string Message { get; set; }
+
+ public bool ShowAgain
+ {
+ get
+ {
+ bool showAgain;
+ if (!Settings.TryGetValue("NotificationBox.ShowAgain", out showAgain))
+ {
+ showAgain = true;
+ ShowAgain = showAgain;
+ }
+
+ return showAgain;
+ }
+
+ set
+ {
+ Settings["NotificationBox.ShowAgain"] = value;
+ }
+ }
+
+ private NotificationBox()
+ {
+ DataContext = this;
+
+ InitializeComponent();
+ }
+
+ public static void Show(string title, string message)
+ {
+ if (_popup != null)
+ {
+ return;
+ }
+
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+ var notificationBox = new NotificationBox
+ {
+ Title = title,
+ Message = message,
+ Width = root.ActualWidth,
+ MaxHeight = root.ActualHeight,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center
+ };
+
+ if (!notificationBox.ShowAgain)
+ return;
+
+ _popup = new Popup
+ {
+ Child = notificationBox,
+ IsOpen = true,
+ };
+ }
+
+ private void buttonOk_Click(object sender, RoutedEventArgs e)
+ {
+ _popup.IsOpen = false;
+ _popup = null;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/BooleanToVisibilityConverter.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/BooleanToVisibilityConverter.cs
new file mode 100644
index 0000000..54fe625
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/BooleanToVisibilityConverter.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+using System.Globalization;
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ public sealed class BooleanToVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var flag = false;
+ if (value is bool)
+ {
+ flag = (bool)value;
+ }
+ else if (value is bool?)
+ {
+ var nullable = (bool?)value;
+ flag = nullable.GetValueOrDefault();
+ }
+ if (parameter != null)
+ {
+ if (bool.Parse((string)parameter))
+ {
+ flag = !flag;
+ }
+ }
+ if (flag)
+ {
+ return Visibility.Visible;
+ }
+ else
+ {
+ return Visibility.Collapsed;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var back = ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
+ if (parameter != null)
+ {
+ if ((bool)parameter)
+ {
+ back = !back;
+ }
+ }
+ return back;
+ }
+ }
+
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml
new file mode 100644
index 0000000..cad21e3
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml.cs
new file mode 100644
index 0000000..0324551
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/ProgressBarWithText.xaml.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ public partial class ProgressBarWithText : UserControl
+ {
+ public ProgressBarWithText()
+ {
+ InitializeComponent();
+
+ stackPanel.DataContext = this;
+ }
+
+ #region ShowProgress
+
+ ///
+ /// ShowProgress Dependency Property
+ ///
+ public static readonly DependencyProperty ShowProgressProperty =
+ DependencyProperty.Register("ShowProgress", typeof(bool), typeof(ProgressBarWithText),
+ new PropertyMetadata((bool)false));
+
+ ///
+ /// Gets or sets the ShowProgress property. This dependency property
+ /// indicates whether to show the progress bar.
+ ///
+ public bool ShowProgress
+ {
+ get { return (bool)GetValue(ShowProgressProperty); }
+ set { SetValue(ShowProgressProperty, value); }
+ }
+
+ #endregion
+
+ #region Text
+
+ ///
+ /// Text Dependency Property
+ ///
+ public static readonly DependencyProperty TextProperty =
+ DependencyProperty.Register("Text", typeof(string), typeof(ProgressBarWithText),
+ new PropertyMetadata((string)""));
+
+ ///
+ /// Gets or sets the Text property. This dependency property
+ /// indicates what is the text that appears above the progress bar.
+ ///
+ public string Text
+ {
+ get { return (string)GetValue(TextProperty); }
+ set { SetValue(TextProperty, value); }
+ }
+
+ #endregion
+
+
+
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/RelativeAnimatingContentControl.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/RelativeAnimatingContentControl.cs
new file mode 100644
index 0000000..ba57127
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ProgressBar/RelativeAnimatingContentControl.cs
@@ -0,0 +1,625 @@
+// (c) Copyright Microsoft Corporation.
+// This source is subject to the Microsoft Public License (Ms-PL).
+// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
+// All other rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+
+// This is a very special primitive control that works around a limitation in
+// the core animation subsystem of Silverlight: there is no way to declare in
+// VSM states relative properties, such as animating from 0 to 33% the width of
+// the control, using double animations for translation.
+//
+// It's a tough problem to solve property, but this primitive, unsupported
+// control does offer a solution based on magic numbers that still allows a
+// designer to make alterations to their animation values to present their
+// vision for custom templates.
+//
+// This is instrumental in offering a Windows Phone ProgressBar implementation
+// that uses the render thread instead of animating UI thread-only properties.
+//
+// For questions, please see
+// http://www.jeff.wilcox.name/performanceprogressbar/
+//
+// This control is licensed Ms-PL and as such comes with no warranties or
+// official support.
+//
+// Style Note
+// - - -
+// The style that must be used with this is present at the bottom of this file.
+//
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ ///
+ /// A very specialized primitive control that works around a specific visual
+ /// state manager issue. The platform does not support relative sized
+ /// translation values, and this special control walks through visual state
+ /// animation storyboards looking for magic numbers to use as percentages.
+ /// This control is not supported, unofficial, and is a hack in many ways.
+ /// It is used to enable a Windows Phone native platform-style progress bar
+ /// experience in indeterminate mode that remains performant.
+ ///
+ public class RelativeAnimatingContentControl : ContentControl
+ {
+ ///
+ /// A simple Epsilon-style value used for trying to determine the magic
+ /// state, if any, of a double.
+ ///
+ private const double SimpleDoubleComparisonEpsilon = 0.000009;
+
+ ///
+ /// The last known width of the control.
+ ///
+ private double _knownWidth;
+
+ ///
+ /// The last known height of the control.
+ ///
+ private double _knownHeight;
+
+ ///
+ /// A set of custom animation adapters used to update the animation
+ /// storyboards when the size of the control changes.
+ ///
+ private List _specialAnimations;
+
+ ///
+ /// Initializes a new instance of the RelativeAnimatingContentControl
+ /// type.
+ ///
+ public RelativeAnimatingContentControl()
+ {
+ SizeChanged += OnSizeChanged;
+ }
+
+ ///
+ /// Handles the size changed event.
+ ///
+ /// The source object.
+ /// The event arguments.
+ private void OnSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (e != null && e.NewSize.Height > 0 && e.NewSize.Width > 0)
+ {
+ _knownWidth = e.NewSize.Width;
+ _knownHeight = e.NewSize.Height;
+
+ Clip = new RectangleGeometry { Rect = new Rect(0, 0, _knownWidth, _knownHeight), };
+
+ UpdateAnyAnimationValues();
+ }
+ }
+
+ ///
+ /// Walks through the known storyboards in the control's template that
+ /// may contain magic double animation values, storing them for future
+ /// use and updates.
+ ///
+ private void UpdateAnyAnimationValues()
+ {
+ if (_knownHeight > 0 && _knownWidth > 0)
+ {
+ // Initially, before any special animations have been found,
+ // the visual state groups of the control must be explored.
+ // By definition they must be at the implementation root of the
+ // control, and this is designed to not walk into any other
+ // depth.
+ if (_specialAnimations == null)
+ {
+ _specialAnimations = new List();
+
+ foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(this))
+ {
+ if (group == null)
+ {
+ continue;
+ }
+ foreach (VisualState state in group.States)
+ {
+ if (state != null)
+ {
+ Storyboard sb = state.Storyboard;
+ if (sb != null)
+ {
+ // Examine all children of the storyboards,
+ // looking for either type of double
+ // animation.
+ foreach (Timeline timeline in sb.Children)
+ {
+ DoubleAnimation da = timeline as DoubleAnimation;
+ DoubleAnimationUsingKeyFrames dakeys = timeline as DoubleAnimationUsingKeyFrames;
+ if (da != null)
+ {
+ ProcessDoubleAnimation(da);
+ }
+ else if (dakeys != null)
+ {
+ ProcessDoubleAnimationWithKeys(dakeys);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Update special animation values relative to the current size.
+ UpdateKnownAnimations();
+ }
+ }
+
+ ///
+ /// Walks through all special animations, updating based on the current
+ /// size of the control.
+ ///
+ private void UpdateKnownAnimations()
+ {
+ foreach (AnimationValueAdapter adapter in _specialAnimations)
+ {
+ adapter.UpdateWithNewDimension(_knownWidth, _knownHeight);
+ }
+ }
+
+ ///
+ /// Processes a double animation with keyframes, looking for known
+ /// special values to store with an adapter.
+ ///
+ /// The double animation using key frames instance.
+ private void ProcessDoubleAnimationWithKeys(DoubleAnimationUsingKeyFrames da)
+ {
+ // Look through all keyframes in the instance.
+ foreach (DoubleKeyFrame frame in da.KeyFrames)
+ {
+ var d = DoubleAnimationFrameAdapter.GetDimensionFromMagicNumber(frame.Value);
+ if (d.HasValue)
+ {
+ _specialAnimations.Add(new DoubleAnimationFrameAdapter(d.Value, frame));
+ }
+ }
+ }
+
+ ///
+ /// Processes a double animation looking for special values.
+ ///
+ /// The double animation instance.
+ private void ProcessDoubleAnimation(DoubleAnimation da)
+ {
+ // Look for a special value in the To property.
+ if (da.To.HasValue)
+ {
+ var d = DoubleAnimationToAdapter.GetDimensionFromMagicNumber(da.To.Value);
+ if (d.HasValue)
+ {
+ _specialAnimations.Add(new DoubleAnimationToAdapter(d.Value, da));
+ }
+ }
+
+ // Look for a special value in the From property.
+ if (da.From.HasValue)
+ {
+ var d = DoubleAnimationFromAdapter.GetDimensionFromMagicNumber(da.To.Value);
+ if (d.HasValue)
+ {
+ _specialAnimations.Add(new DoubleAnimationFromAdapter(d.Value, da));
+ }
+ }
+ }
+
+ #region Private animation updating system
+ ///
+ /// A selection of dimensions of interest for updating an animation.
+ ///
+ private enum DoubleAnimationDimension
+ {
+ ///
+ /// The width (horizontal) dimension.
+ ///
+ Width,
+
+ ///
+ /// The height (vertical) dimension.
+ ///
+ Height,
+ }
+
+ ///
+ /// A simple class designed to store information about a specific
+ /// animation instance and its properties. Able to update the values at
+ /// runtime.
+ ///
+ private abstract class AnimationValueAdapter
+ {
+ ///
+ /// Gets or sets the original double value.
+ ///
+ protected double OriginalValue { get; set; }
+
+ ///
+ /// Initializes a new instance of the AnimationValueAdapter type.
+ ///
+ /// The dimension of interest for updates.
+ public AnimationValueAdapter(DoubleAnimationDimension dimension)
+ {
+ Dimension = dimension;
+ }
+
+ ///
+ /// Gets the dimension of interest for the control.
+ ///
+ public DoubleAnimationDimension Dimension { get; private set; }
+
+ ///
+ /// Updates the original instance based on new dimension information
+ /// from the control. Takes both and allows the subclass to make the
+ /// decision on which ratio, values, and dimension to use.
+ ///
+ /// The width of the control.
+ /// The height of the control.
+ public abstract void UpdateWithNewDimension(double width, double height);
+ }
+
+ private abstract class GeneralAnimationValueAdapter : AnimationValueAdapter
+ {
+ ///
+ /// Stores the animation instance.
+ ///
+ protected T Instance { get; set; }
+
+ ///
+ /// Gets the value of the underlying property of interest.
+ ///
+ /// Returns the value of the property.
+ protected abstract double GetValue();
+
+ ///
+ /// Sets the value for the underlying property of interest.
+ ///
+ /// The new value for the property.
+ protected abstract void SetValue(double newValue);
+
+ ///
+ /// Gets the initial value (minus the magic number portion) that the
+ /// designer stored within the visual state animation property.
+ ///
+ protected double InitialValue { get; private set; }
+
+ ///
+ /// The ratio based on the original magic value, used for computing
+ /// the updated animation property of interest when the size of the
+ /// control changes.
+ ///
+ private double _ratio;
+
+ ///
+ /// Initializes a new instance of the GeneralAnimationValueAdapter
+ /// type.
+ ///
+ /// The dimension of interest.
+ /// The animation type instance.
+ public GeneralAnimationValueAdapter(DoubleAnimationDimension d, T instance)
+ : base(d)
+ {
+ Instance = instance;
+
+ InitialValue = StripMagicNumberOff(GetValue());
+ _ratio = InitialValue / 100;
+ }
+
+ ///
+ /// Approximately removes the magic number state from a value.
+ ///
+ /// The initial number.
+ /// Returns a double with an adjustment for the magic
+ /// portion of the number.
+ public double StripMagicNumberOff(double number)
+ {
+ return Dimension == DoubleAnimationDimension.Width ? number - .1 : number - .2;
+ }
+
+ ///
+ /// Retrieves the dimension, if any, from the number. If the number
+ /// is not magic, null is returned instead.
+ ///
+ /// The double value.
+ /// Returs a double animation dimension, if the number was
+ /// partially magic; otherwise, returns null.
+ public static DoubleAnimationDimension? GetDimensionFromMagicNumber(double number)
+ {
+ double floor = Math.Floor(number);
+ double remainder = number - floor;
+
+ if (remainder >= .1 - SimpleDoubleComparisonEpsilon && remainder <= .1 + SimpleDoubleComparisonEpsilon)
+ {
+ return DoubleAnimationDimension.Width;
+ }
+ if (remainder >= .2 - SimpleDoubleComparisonEpsilon && remainder <= .2 + SimpleDoubleComparisonEpsilon)
+ {
+ return DoubleAnimationDimension.Height;
+ }
+ return null;
+ }
+
+ ///
+ /// Updates the animation instance based on the dimensions of the
+ /// control.
+ ///
+ /// The width of the control.
+ /// The height of the control.
+ public override void UpdateWithNewDimension(double width, double height)
+ {
+ double size = Dimension == DoubleAnimationDimension.Width ? width : height;
+ UpdateValue(size);
+ }
+
+ ///
+ /// Updates the value of the property.
+ ///
+ /// The size of interest to use with a ratio
+ /// computation.
+ private void UpdateValue(double sizeToUse)
+ {
+ SetValue(sizeToUse * _ratio);
+ }
+ }
+
+ ///
+ /// Adapter for DoubleAnimation's To property.
+ ///
+ private class DoubleAnimationToAdapter : GeneralAnimationValueAdapter
+ {
+ ///
+ /// Gets the value of the underlying property of interest.
+ ///
+ /// Returns the value of the property.
+ protected override double GetValue()
+ {
+ return (double)Instance.To;
+ }
+
+ ///
+ /// Sets the value for the underlying property of interest.
+ ///
+ /// The new value for the property.
+ protected override void SetValue(double newValue)
+ {
+ Instance.To = newValue;
+ }
+
+ ///
+ /// Initializes a new instance of the DoubleAnimationToAdapter type.
+ ///
+ /// The dimension of interest.
+ /// The instance of the animation type.
+ public DoubleAnimationToAdapter(DoubleAnimationDimension dimension, DoubleAnimation instance)
+ : base(dimension, instance)
+ {
+ }
+ }
+
+ ///
+ /// Adapter for DoubleAnimation's From property.
+ ///
+ private class DoubleAnimationFromAdapter : GeneralAnimationValueAdapter
+ {
+ ///
+ /// Gets the value of the underlying property of interest.
+ ///
+ /// Returns the value of the property.
+ protected override double GetValue()
+ {
+ return (double)Instance.From;
+ }
+
+ ///
+ /// Sets the value for the underlying property of interest.
+ ///
+ /// The new value for the property.
+ protected override void SetValue(double newValue)
+ {
+ Instance.From = newValue;
+ }
+
+ ///
+ /// Initializes a new instance of the DoubleAnimationFromAdapter
+ /// type.
+ ///
+ /// The dimension of interest.
+ /// The instance of the animation type.
+ public DoubleAnimationFromAdapter(DoubleAnimationDimension dimension, DoubleAnimation instance)
+ : base(dimension, instance)
+ {
+ }
+ }
+
+ ///
+ /// Adapter for double key frames.
+ ///
+ private class DoubleAnimationFrameAdapter : GeneralAnimationValueAdapter
+ {
+ ///
+ /// Gets the value of the underlying property of interest.
+ ///
+ /// Returns the value of the property.
+ protected override double GetValue()
+ {
+ return Instance.Value;
+ }
+
+ ///
+ /// Sets the value for the underlying property of interest.
+ ///
+ /// The new value for the property.
+ protected override void SetValue(double newValue)
+ {
+ Instance.Value = newValue;
+ }
+
+ ///
+ /// Initializes a new instance of the DoubleAnimationFrameAdapter
+ /// type.
+ ///
+ /// The dimension of interest.
+ /// The instance of the animation type.
+ public DoubleAnimationFrameAdapter(DoubleAnimationDimension dimension, DoubleKeyFrame frame)
+ : base(dimension, frame)
+ {
+ }
+ }
+ #endregion
+ }
+
+ /*
+ This is the style that should be used with the control. Make sure to define
+ the XMLNS at the top of the style file similar to this:
+ xmlns:unsupported="clr-namespace:WindowsPhone.Recipes.Push.Client.Controls"
+
+
+
+ */
+}
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml
new file mode 100644
index 0000000..1406e3c
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml.cs
new file mode 100644
index 0000000..1023faa
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/PushSettingsControl.xaml.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+using System.Xml.Linq;
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ public partial class PushSettingsControl : UserControl
+ {
+ public PushSettingsControl()
+ {
+ DataContext = PushContext.Current;
+
+ InitializeComponent();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ViewTransitions.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ViewTransitions.cs
new file mode 100644
index 0000000..8b9640d
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Controls/ViewTransitions.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Collections.Generic;
+
+namespace WindowsPhone.Recipes.Push.Client.Controls
+{
+ public class ViewTransitions
+ {
+ private class ViewTransition
+ {
+ public T To { get; set; }
+ public Action Action { get; set; }
+ }
+
+ public T _viewState;
+ private readonly Dictionary _transitions = new Dictionary();
+
+ public ViewTransitions(T initialState)
+ {
+ _viewState = initialState;
+ }
+
+ public void AddTransition(T from, T to, Action action)
+ {
+ _transitions[from] = new ViewTransition { To = to, Action = action };
+ }
+
+ public void Transition()
+ {
+ var transition = _transitions[_viewState];
+ _viewState = transition.To;
+ transition.Action();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Converters/BoolBrushConverter.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Converters/BoolBrushConverter.cs
new file mode 100644
index 0000000..4ae5888
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Converters/BoolBrushConverter.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+
+namespace WindowsPhone.Recipes.Push.Client.Converters
+{
+ public class BoolBrushConverter : IValueConverter
+ {
+ private static readonly Brush DisabledBrush = new SolidColorBrush
+ {
+ Color = Colors.Black,
+ Opacity = 0.4
+ };
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return object.Equals(value, true) ? null : DisabledBrush;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ExceptionExtensions.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ExceptionExtensions.cs
new file mode 100644
index 0000000..f223c07
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ExceptionExtensions.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public static class ExceptionExtensions
+ {
+ public static void Show(this Exception ex, string title = "Error")
+ {
+ MessageBox.Show(ex.Message, title, MessageBoxButton.OK);
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml
new file mode 100644
index 0000000..f75dc8b
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml.cs
new file mode 100644
index 0000000..4b172fb
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/MainPage.xaml.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+using System.Windows.Navigation;
+
+using Microsoft.Phone.Controls;
+using WindowsPhone.Recipes.Push.Client.Views;
+using WindowsPhone.Recipes.Push.Client.Controls;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public partial class MainPage : PhoneApplicationPage
+ {
+ #region Fields
+
+ private readonly IsolatedStorageSettings Settings = IsolatedStorageSettings.ApplicationSettings;
+ private const string ChannelName = "OneTimePatternChannel";
+ private const string ServiceName = "WindowsPhone.Recipes.Push.Server.PushService";
+
+ private static readonly Uri[] AllowedDomains =
+ {
+ new Uri(App.ServerAddress)
+ };
+
+ private readonly ViewTransitions _viewTransitions;
+
+ #endregion
+
+ #region Properties
+
+ private UIElement ActiveView
+ {
+ get { return activeView.Child; }
+ set { activeView.Child = value; }
+ }
+
+ #endregion
+
+ #region Ctor
+
+ public MainPage()
+ {
+ InitializeComponent();
+
+ var viewState = CheckIfFirstTimeLoaded() ? ViewState.FirstInitial : ViewState.Initial;
+ _viewTransitions = new ViewTransitions(viewState);
+ InitializeViewTransitions();
+ }
+
+ #endregion
+
+ #region Overrides
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ var pushContext = new PushContext(ChannelName, ServiceName, AllowedDomains, Dispatcher);
+
+ _viewTransitions.Transition();
+
+ base.OnNavigatedTo(e);
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ private void userLoginView_Login(object sender, LoginEventArgs e)
+ {
+ if (e.Exception != null)
+ {
+ e.Exception.Show("Login");
+ return;
+ }
+
+ var userLoginView = sender as UserLoginView;
+ userLoginView.Login -= userLoginView_Login;
+
+ _viewTransitions.Transition();
+ }
+
+ private void button_Click(object sender, RoutedEventArgs e)
+ {
+ _viewTransitions.Transition();
+ }
+
+ #endregion
+
+ #region Privates
+
+ private bool CheckIfFirstTimeLoaded()
+ {
+ object unused;
+ if (!Settings.TryGetValue("MainPage.Loaded", out unused))
+ {
+ Settings["MainPage.Loaded"] = null;
+ return true;
+ }
+
+ return false;
+ }
+
+ private void DisplayUserLoginView()
+ {
+ PageTitle.Text = "registration";
+ button.Visibility = Visibility.Collapsed;
+ var userLoginView = new UserLoginView
+ {
+ UserName = "tomer.shamam"
+ };
+
+ userLoginView.Login += userLoginView_Login;
+ ActiveView = userLoginView;
+ }
+
+ private void DisplayPushSettingsView()
+ {
+ PageTitle.Text = "push settings";
+ button.Content = "OK";
+ button.Visibility = Visibility.Visible;
+ ActiveView = new PushSettingsView();
+ }
+
+ private void DisplayInboxView()
+ {
+ PageTitle.Text = "server status";
+ button.Content = "Settings";
+ button.Visibility = Visibility.Visible;
+ ActiveView = new InboxView();
+ }
+
+ private void InitializeViewTransitions()
+ {
+ _viewTransitions.AddTransition(ViewState.FirstInitial, ViewState.FirstSettings, DisplayPushSettingsView);
+ _viewTransitions.AddTransition(ViewState.Initial, ViewState.Login, DisplayUserLoginView);
+ _viewTransitions.AddTransition(ViewState.FirstSettings, ViewState.Login, DisplayUserLoginView);
+ _viewTransitions.AddTransition(ViewState.Login, ViewState.Inbox, DisplayInboxView);
+ _viewTransitions.AddTransition(ViewState.Settings, ViewState.Inbox, DisplayInboxView);
+ _viewTransitions.AddTransition(ViewState.Inbox, ViewState.Settings, DisplayPushSettingsView);
+ }
+
+ #endregion
+
+ #region ViewState
+
+ [Flags]
+ private enum ViewState
+ {
+ FirstTime = 1,
+ Initial = 2,
+ Settings = 4,
+ Login = 8,
+ Inbox = 16,
+ FirstInitial = FirstTime | Initial,
+ FirstSettings = FirstTime | Settings
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AppManifest.xml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AppManifest.xml
new file mode 100644
index 0000000..a955232
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AssemblyInfo.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..6173f5a
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+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("WindowsPhone.Recipes.Push.Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("WindowsPhone.Recipes.Push.Client")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[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("499d0817-8efe-4199-b5dc-e397b79dddc0")]
+
+// 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 Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/WMAppManifest.xml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/WMAppManifest.xml
new file mode 100644
index 0000000..e18f5d6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Properties/WMAppManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+ ApplicationIcon.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Background.png
+ 0
+ Push Patterns
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContext.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContext.cs
new file mode 100644
index 0000000..fa5d881
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContext.cs
@@ -0,0 +1,360 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Notification;
+using System.Windows.Threading;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO.IsolatedStorage;
+using System.ComponentModel;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public sealed class PushContext : INotifyPropertyChanged
+ {
+ #region Fields
+
+ private readonly IsolatedStorageSettings Settings = IsolatedStorageSettings.ApplicationSettings;
+ private static PushContext _current;
+ private bool _isConnected;
+
+ #endregion
+
+ #region Properties
+ private Dispatcher Dispatcher { get; set; }
+
+ public string ChannelName { get; private set; }
+ public string ServiceName { get; private set; }
+ public IList AllowedDomains { get; private set; }
+ public HttpNotificationChannel NotificationChannel { get; private set; }
+
+ public static PushContext Current
+ {
+ get { return _current; }
+ }
+
+ public bool IsConnected
+ {
+ get { return _isConnected; }
+ set
+ {
+ if (_isConnected != value)
+ {
+ _isConnected = value;
+ NotifyPropertyChanged("IsConnected");
+ }
+ }
+ }
+
+ public bool IsPushEnabled
+ {
+ get { return GetOrCreate("PushContext.IsPushEnabled", false); }
+ set
+ {
+ SetOrCreate("PushContext.IsPushEnabled", value);
+ UpdateNotificationBindings();
+ NotifyPropertyChanged("IsPushEnabled");
+ }
+ }
+
+ public bool IsTileEnabled
+ {
+ get { return GetOrCreate("PushContext.IsTileEnabled", true); }
+ set
+ {
+ SetOrCreate("PushContext.IsTileEnabled", value);
+ UpdateNotificationBindings();
+ NotifyPropertyChanged("IsTileEnabled");
+ }
+ }
+
+ public bool IsToastEnabled
+ {
+ get { return GetOrCreate("PushContext.IsToastEnabled", true); }
+ set
+ {
+ SetOrCreate("PushContext.IsToastEnabled", value);
+ UpdateNotificationBindings();
+ NotifyPropertyChanged("IsToastEnabled");
+ }
+ }
+
+ public bool IsRawEnabled
+ {
+ get { return GetOrCreate("PushContext.IsRawEnabled", true); }
+ set
+ {
+ SetOrCreate("PushContext.IsRawEnabled", value);
+ NotifyPropertyChanged("IsRawEnabled");
+ }
+ }
+ #endregion
+
+ #region Events
+ public event EventHandler Error;
+ public event EventHandler ChannelPrepared;
+ public event EventHandler RawNotification;
+ public event PropertyChangedEventHandler PropertyChanged = delegate { };
+ #endregion
+
+ #region Ctor
+
+ public PushContext(string channelName, string serviceName, IList allowedDomains, Dispatcher dispatcher)
+ {
+ if (_current != null)
+ {
+ throw new InvalidOperationException("There should be no more than one push context.");
+ }
+
+ ChannelName = channelName;
+ ServiceName = serviceName;
+ AllowedDomains = allowedDomains;
+ Dispatcher = dispatcher;
+
+ _current = this;
+ }
+
+ #endregion
+
+ #region Public Methods
+ public void Connect(Action prepared)
+ {
+ if (IsConnected)
+ {
+ prepared(NotificationChannel);
+ return;
+ }
+
+ try
+ {
+ // First, try to pick up an existing channel.
+ NotificationChannel = HttpNotificationChannel.Find(ChannelName);
+
+ if (NotificationChannel == null)
+ {
+ // Create new channel and subscribe events.
+ CreateChannel(prepared);
+ }
+ else
+ {
+ // Channel exists, no need to create a new one.
+ SubscribeToNotificationEvents();
+ PrepareChannel(prepared);
+ }
+
+ IsConnected = true;
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ public void Disconnect()
+ {
+ if (!IsConnected)
+ {
+ return;
+ }
+
+ try
+ {
+ if (NotificationChannel != null)
+ {
+ UnbindFromTileNotifications();
+ UnbindFromToastNotifications();
+ NotificationChannel.Close();
+ }
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ finally
+ {
+ NotificationChannel = null;
+ IsConnected = false;
+ }
+ }
+ #endregion
+
+ #region Privates
+ ///
+ /// Create channel, subscribe to channel events and open the channel.
+ ///
+ private void CreateChannel(Action prepared)
+ {
+ // Create a new channel.
+ NotificationChannel = new HttpNotificationChannel(ChannelName, ServiceName);
+
+ // Register to UriUpdated event. This occurs when channel successfully opens.
+ NotificationChannel.ChannelUriUpdated += (s, e) => Dispatcher.BeginInvoke(() => PrepareChannel(prepared));
+
+ SubscribeToNotificationEvents();
+
+ // Trying to Open the channel.
+ NotificationChannel.Open();
+ }
+
+ private void SubscribeToNotificationEvents()
+ {
+ // Register to raw notifications.
+ NotificationChannel.HttpNotificationReceived += (s, e) =>
+ {
+ if (IsPushEnabled & IsRawEnabled)
+ {
+ Dispatcher.BeginInvoke(() => OnRawNotification(e));
+ }
+ };
+ }
+
+ private void OnRawNotification(HttpNotificationEventArgs e)
+ {
+ if (RawNotification != null)
+ {
+ RawNotification(this, e);
+ }
+ }
+
+ private void PrepareChannel(Action prepared)
+ {
+ try
+ {
+ // OnChannelPrepared(new PushContextEventArgs(NotificationChannel));
+ prepared(NotificationChannel);
+ UpdateNotificationBindings();
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ private void OnError(Exception exception)
+ {
+ if (Error != null)
+ {
+ Error(this, new PushContextErrorEventArgs(exception));
+ }
+ }
+
+ private void OnChannelPrepared(PushContextEventArgs args)
+ {
+ if (ChannelPrepared != null)
+ {
+ ChannelPrepared(this, args);
+ }
+ }
+
+ private void BindToTileNotifications()
+ {
+ try
+ {
+ if (NotificationChannel != null && !NotificationChannel.IsShellTileBound)
+ {
+ var listOfAllowedDomains = new Collection(AllowedDomains);
+ NotificationChannel.BindToShellTile(listOfAllowedDomains);
+ }
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ private void BindToToastNotifications()
+ {
+ try
+ {
+ if (NotificationChannel != null && !NotificationChannel.IsShellToastBound)
+ {
+ NotificationChannel.BindToShellToast();
+ }
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ private void UnbindFromTileNotifications()
+ {
+ try
+ {
+ if (NotificationChannel.IsShellTileBound)
+ {
+ NotificationChannel.UnbindToShellTile();
+ }
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ private void UnbindFromToastNotifications()
+ {
+ try
+ {
+ if (NotificationChannel.IsShellToastBound)
+ {
+ NotificationChannel.UnbindToShellToast();
+ }
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ private void UpdateNotificationBindings()
+ {
+ if (IsPushEnabled && IsTileEnabled)
+ {
+ BindToTileNotifications();
+ }
+ else
+ {
+ UnbindFromTileNotifications();
+ }
+
+ if (IsPushEnabled && IsToastEnabled)
+ {
+ BindToToastNotifications();
+ }
+ else
+ {
+ UnbindFromToastNotifications();
+ }
+ }
+
+ private T GetOrCreate(string key, T defaultValue = default(T))
+ {
+ T value;
+ if (Settings.TryGetValue(key, out value))
+ {
+ return value;
+ }
+
+ return defaultValue;
+ }
+
+ private void SetOrCreate(string key, T value)
+ {
+ Settings[key] = value;
+ }
+
+ private void NotifyPropertyChanged(string propertyName)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextErrorEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextErrorEventArgs.cs
new file mode 100644
index 0000000..8c29892
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextErrorEventArgs.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public class PushContextErrorEventArgs : EventArgs
+ {
+ public Exception Exception { get; private set; }
+
+ public PushContextErrorEventArgs(Exception exception)
+ {
+ Exception = exception;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextEventArgs.cs
new file mode 100644
index 0000000..ca4a498
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/PushContextEventArgs.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Phone.Notification;
+
+namespace WindowsPhone.Recipes.Push.Client
+{
+ public class PushContextEventArgs : EventArgs
+ {
+ public HttpNotificationChannel NotificationChannel { get; private set; }
+
+ internal PushContextEventArgs(HttpNotificationChannel channel)
+ {
+ NotificationChannel = channel;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground1.jpg b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground1.jpg
new file mode 100644
index 0000000..0ddc419
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground1.jpg differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground2.jpg b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground2.jpg
new file mode 100644
index 0000000..ff28731
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground2.jpg differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground3.jpg b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground3.jpg
new file mode 100644
index 0000000..9e19400
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Resources/TileImages/TileBackground3.jpg differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.cs
new file mode 100644
index 0000000..ed38744
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.cs
@@ -0,0 +1,444 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+//
+// This code was auto-generated by Microsoft.Silverlight.Phone.ServiceReference, version 3.7.0.0
+//
+namespace WindowsPhone.Recipes.Push.Client.Services {
+ using System.Runtime.Serialization;
+
+
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+ [System.Runtime.Serialization.DataContractAttribute(Name="ServerInfo", Namespace="http://schemas.datacontract.org/2004/07/WindowsPhone.Recipes.Push.Server.Models")]
+ public partial class ServerInfo : object, System.ComponentModel.INotifyPropertyChanged {
+
+ private int CounterField;
+
+ private string PushPatternField;
+
+ [System.Runtime.Serialization.DataMemberAttribute()]
+ public int Counter {
+ get {
+ return this.CounterField;
+ }
+ set {
+ if ((this.CounterField.Equals(value) != true)) {
+ this.CounterField = value;
+ this.RaisePropertyChanged("Counter");
+ }
+ }
+ }
+
+ [System.Runtime.Serialization.DataMemberAttribute()]
+ public string PushPattern {
+ get {
+ return this.PushPatternField;
+ }
+ set {
+ if ((object.ReferenceEquals(this.PushPatternField, value) != true)) {
+ this.PushPatternField = value;
+ this.RaisePropertyChanged("PushPattern");
+ }
+ }
+ }
+
+ public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
+
+ protected void RaisePropertyChanged(string propertyName) {
+ System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
+ if ((propertyChanged != null)) {
+ propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
+ }
+ }
+ }
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+ [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Services.IPushService")]
+ public interface IPushService {
+
+ [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IPushService/Register", ReplyAction="http://tempuri.org/IPushService/RegisterResponse")]
+ System.IAsyncResult BeginRegister(string userName, System.Uri channelUri, System.AsyncCallback callback, object asyncState);
+
+ void EndRegister(System.IAsyncResult result);
+
+ [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IPushService/GetServerInfo", ReplyAction="http://tempuri.org/IPushService/GetServerInfoResponse")]
+ System.IAsyncResult BeginGetServerInfo(System.AsyncCallback callback, object asyncState);
+
+ WindowsPhone.Recipes.Push.Client.Services.ServerInfo EndGetServerInfo(System.IAsyncResult result);
+
+ [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IPushService/UpdateTile", ReplyAction="http://tempuri.org/IPushService/UpdateTileResponse")]
+ System.IAsyncResult BeginUpdateTile(System.Uri channelUri, string parameter, System.AsyncCallback callback, object asyncState);
+
+ void EndUpdateTile(System.IAsyncResult result);
+ }
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+ public interface IPushServiceChannel : WindowsPhone.Recipes.Push.Client.Services.IPushService, System.ServiceModel.IClientChannel {
+ }
+
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+ public partial class GetServerInfoCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
+
+ private object[] results;
+
+ public GetServerInfoCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState) {
+ this.results = results;
+ }
+
+ public WindowsPhone.Recipes.Push.Client.Services.ServerInfo Result {
+ get {
+ base.RaiseExceptionIfNecessary();
+ return ((WindowsPhone.Recipes.Push.Client.Services.ServerInfo)(this.results[0]));
+ }
+ }
+ }
+
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+ public partial class PushServiceClient : System.ServiceModel.ClientBase, WindowsPhone.Recipes.Push.Client.Services.IPushService {
+
+ private BeginOperationDelegate onBeginRegisterDelegate;
+
+ private EndOperationDelegate onEndRegisterDelegate;
+
+ private System.Threading.SendOrPostCallback onRegisterCompletedDelegate;
+
+ private BeginOperationDelegate onBeginGetServerInfoDelegate;
+
+ private EndOperationDelegate onEndGetServerInfoDelegate;
+
+ private System.Threading.SendOrPostCallback onGetServerInfoCompletedDelegate;
+
+ private BeginOperationDelegate onBeginUpdateTileDelegate;
+
+ private EndOperationDelegate onEndUpdateTileDelegate;
+
+ private System.Threading.SendOrPostCallback onUpdateTileCompletedDelegate;
+
+ private BeginOperationDelegate onBeginOpenDelegate;
+
+ private EndOperationDelegate onEndOpenDelegate;
+
+ private System.Threading.SendOrPostCallback onOpenCompletedDelegate;
+
+ private BeginOperationDelegate onBeginCloseDelegate;
+
+ private EndOperationDelegate onEndCloseDelegate;
+
+ private System.Threading.SendOrPostCallback onCloseCompletedDelegate;
+
+ public PushServiceClient() {
+ }
+
+ public PushServiceClient(string endpointConfigurationName) :
+ base(endpointConfigurationName) {
+ }
+
+ public PushServiceClient(string endpointConfigurationName, string remoteAddress) :
+ base(endpointConfigurationName, remoteAddress) {
+ }
+
+ public PushServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(endpointConfigurationName, remoteAddress) {
+ }
+
+ public PushServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(binding, remoteAddress) {
+ }
+
+ public System.Net.CookieContainer CookieContainer {
+ get {
+ System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty();
+ if ((httpCookieContainerManager != null)) {
+ return httpCookieContainerManager.CookieContainer;
+ }
+ else {
+ return null;
+ }
+ }
+ set {
+ System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty();
+ if ((httpCookieContainerManager != null)) {
+ httpCookieContainerManager.CookieContainer = value;
+ }
+ else {
+ throw new System.InvalidOperationException("Unable to set the CookieContainer. Please make sure the binding contains an HttpC" +
+ "ookieContainerBindingElement.");
+ }
+ }
+ }
+
+ public event System.EventHandler RegisterCompleted;
+
+ public event System.EventHandler GetServerInfoCompleted;
+
+ public event System.EventHandler UpdateTileCompleted;
+
+ public event System.EventHandler OpenCompleted;
+
+ public event System.EventHandler CloseCompleted;
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ System.IAsyncResult WindowsPhone.Recipes.Push.Client.Services.IPushService.BeginRegister(string userName, System.Uri channelUri, System.AsyncCallback callback, object asyncState) {
+ return base.Channel.BeginRegister(userName, channelUri, callback, asyncState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ void WindowsPhone.Recipes.Push.Client.Services.IPushService.EndRegister(System.IAsyncResult result) {
+ base.Channel.EndRegister(result);
+ }
+
+ private System.IAsyncResult OnBeginRegister(object[] inValues, System.AsyncCallback callback, object asyncState) {
+ string userName = ((string)(inValues[0]));
+ System.Uri channelUri = ((System.Uri)(inValues[1]));
+ return ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).BeginRegister(userName, channelUri, callback, asyncState);
+ }
+
+ private object[] OnEndRegister(System.IAsyncResult result) {
+ ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).EndRegister(result);
+ return null;
+ }
+
+ private void OnRegisterCompleted(object state) {
+ if ((this.RegisterCompleted != null)) {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.RegisterCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void RegisterAsync(string userName, System.Uri channelUri) {
+ this.RegisterAsync(userName, channelUri, null);
+ }
+
+ public void RegisterAsync(string userName, System.Uri channelUri, object userState) {
+ if ((this.onBeginRegisterDelegate == null)) {
+ this.onBeginRegisterDelegate = new BeginOperationDelegate(this.OnBeginRegister);
+ }
+ if ((this.onEndRegisterDelegate == null)) {
+ this.onEndRegisterDelegate = new EndOperationDelegate(this.OnEndRegister);
+ }
+ if ((this.onRegisterCompletedDelegate == null)) {
+ this.onRegisterCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnRegisterCompleted);
+ }
+ base.InvokeAsync(this.onBeginRegisterDelegate, new object[] {
+ userName,
+ channelUri}, this.onEndRegisterDelegate, this.onRegisterCompletedDelegate, userState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ System.IAsyncResult WindowsPhone.Recipes.Push.Client.Services.IPushService.BeginGetServerInfo(System.AsyncCallback callback, object asyncState) {
+ return base.Channel.BeginGetServerInfo(callback, asyncState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ WindowsPhone.Recipes.Push.Client.Services.ServerInfo WindowsPhone.Recipes.Push.Client.Services.IPushService.EndGetServerInfo(System.IAsyncResult result) {
+ return base.Channel.EndGetServerInfo(result);
+ }
+
+ private System.IAsyncResult OnBeginGetServerInfo(object[] inValues, System.AsyncCallback callback, object asyncState) {
+ return ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).BeginGetServerInfo(callback, asyncState);
+ }
+
+ private object[] OnEndGetServerInfo(System.IAsyncResult result) {
+ WindowsPhone.Recipes.Push.Client.Services.ServerInfo retVal = ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).EndGetServerInfo(result);
+ return new object[] {
+ retVal};
+ }
+
+ private void OnGetServerInfoCompleted(object state) {
+ if ((this.GetServerInfoCompleted != null)) {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.GetServerInfoCompleted(this, new GetServerInfoCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void GetServerInfoAsync() {
+ this.GetServerInfoAsync(null);
+ }
+
+ public void GetServerInfoAsync(object userState) {
+ if ((this.onBeginGetServerInfoDelegate == null)) {
+ this.onBeginGetServerInfoDelegate = new BeginOperationDelegate(this.OnBeginGetServerInfo);
+ }
+ if ((this.onEndGetServerInfoDelegate == null)) {
+ this.onEndGetServerInfoDelegate = new EndOperationDelegate(this.OnEndGetServerInfo);
+ }
+ if ((this.onGetServerInfoCompletedDelegate == null)) {
+ this.onGetServerInfoCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnGetServerInfoCompleted);
+ }
+ base.InvokeAsync(this.onBeginGetServerInfoDelegate, null, this.onEndGetServerInfoDelegate, this.onGetServerInfoCompletedDelegate, userState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ System.IAsyncResult WindowsPhone.Recipes.Push.Client.Services.IPushService.BeginUpdateTile(System.Uri channelUri, string parameter, System.AsyncCallback callback, object asyncState) {
+ return base.Channel.BeginUpdateTile(channelUri, parameter, callback, asyncState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ void WindowsPhone.Recipes.Push.Client.Services.IPushService.EndUpdateTile(System.IAsyncResult result) {
+ base.Channel.EndUpdateTile(result);
+ }
+
+ private System.IAsyncResult OnBeginUpdateTile(object[] inValues, System.AsyncCallback callback, object asyncState) {
+ System.Uri channelUri = ((System.Uri)(inValues[0]));
+ string parameter = ((string)(inValues[1]));
+ return ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).BeginUpdateTile(channelUri, parameter, callback, asyncState);
+ }
+
+ private object[] OnEndUpdateTile(System.IAsyncResult result) {
+ ((WindowsPhone.Recipes.Push.Client.Services.IPushService)(this)).EndUpdateTile(result);
+ return null;
+ }
+
+ private void OnUpdateTileCompleted(object state) {
+ if ((this.UpdateTileCompleted != null)) {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.UpdateTileCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void UpdateTileAsync(System.Uri channelUri, string parameter) {
+ this.UpdateTileAsync(channelUri, parameter, null);
+ }
+
+ public void UpdateTileAsync(System.Uri channelUri, string parameter, object userState) {
+ if ((this.onBeginUpdateTileDelegate == null)) {
+ this.onBeginUpdateTileDelegate = new BeginOperationDelegate(this.OnBeginUpdateTile);
+ }
+ if ((this.onEndUpdateTileDelegate == null)) {
+ this.onEndUpdateTileDelegate = new EndOperationDelegate(this.OnEndUpdateTile);
+ }
+ if ((this.onUpdateTileCompletedDelegate == null)) {
+ this.onUpdateTileCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnUpdateTileCompleted);
+ }
+ base.InvokeAsync(this.onBeginUpdateTileDelegate, new object[] {
+ channelUri,
+ parameter}, this.onEndUpdateTileDelegate, this.onUpdateTileCompletedDelegate, userState);
+ }
+
+ private System.IAsyncResult OnBeginOpen(object[] inValues, System.AsyncCallback callback, object asyncState) {
+ return ((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(callback, asyncState);
+ }
+
+ private object[] OnEndOpen(System.IAsyncResult result) {
+ ((System.ServiceModel.ICommunicationObject)(this)).EndOpen(result);
+ return null;
+ }
+
+ private void OnOpenCompleted(object state) {
+ if ((this.OpenCompleted != null)) {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.OpenCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void OpenAsync() {
+ this.OpenAsync(null);
+ }
+
+ public void OpenAsync(object userState) {
+ if ((this.onBeginOpenDelegate == null)) {
+ this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
+ }
+ if ((this.onEndOpenDelegate == null)) {
+ this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
+ }
+ if ((this.onOpenCompletedDelegate == null)) {
+ this.onOpenCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnOpenCompleted);
+ }
+ base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, userState);
+ }
+
+ private System.IAsyncResult OnBeginClose(object[] inValues, System.AsyncCallback callback, object asyncState) {
+ return ((System.ServiceModel.ICommunicationObject)(this)).BeginClose(callback, asyncState);
+ }
+
+ private object[] OnEndClose(System.IAsyncResult result) {
+ ((System.ServiceModel.ICommunicationObject)(this)).EndClose(result);
+ return null;
+ }
+
+ private void OnCloseCompleted(object state) {
+ if ((this.CloseCompleted != null)) {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.CloseCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void CloseAsync() {
+ this.CloseAsync(null);
+ }
+
+ public void CloseAsync(object userState) {
+ if ((this.onBeginCloseDelegate == null)) {
+ this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
+ }
+ if ((this.onEndCloseDelegate == null)) {
+ this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
+ }
+ if ((this.onCloseCompletedDelegate == null)) {
+ this.onCloseCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnCloseCompleted);
+ }
+ base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, userState);
+ }
+
+ protected override WindowsPhone.Recipes.Push.Client.Services.IPushService CreateChannel() {
+ return new PushServiceClientChannel(this);
+ }
+
+ private class PushServiceClientChannel : ChannelBase, WindowsPhone.Recipes.Push.Client.Services.IPushService {
+
+ public PushServiceClientChannel(System.ServiceModel.ClientBase client) :
+ base(client) {
+ }
+
+ public System.IAsyncResult BeginRegister(string userName, System.Uri channelUri, System.AsyncCallback callback, object asyncState) {
+ object[] _args = new object[2];
+ _args[0] = userName;
+ _args[1] = channelUri;
+ System.IAsyncResult _result = base.BeginInvoke("Register", _args, callback, asyncState);
+ return _result;
+ }
+
+ public void EndRegister(System.IAsyncResult result) {
+ object[] _args = new object[0];
+ base.EndInvoke("Register", _args, result);
+ }
+
+ public System.IAsyncResult BeginGetServerInfo(System.AsyncCallback callback, object asyncState) {
+ object[] _args = new object[0];
+ System.IAsyncResult _result = base.BeginInvoke("GetServerInfo", _args, callback, asyncState);
+ return _result;
+ }
+
+ public WindowsPhone.Recipes.Push.Client.Services.ServerInfo EndGetServerInfo(System.IAsyncResult result) {
+ object[] _args = new object[0];
+ WindowsPhone.Recipes.Push.Client.Services.ServerInfo _result = ((WindowsPhone.Recipes.Push.Client.Services.ServerInfo)(base.EndInvoke("GetServerInfo", _args, result)));
+ return _result;
+ }
+
+ public System.IAsyncResult BeginUpdateTile(System.Uri channelUri, string parameter, System.AsyncCallback callback, object asyncState) {
+ object[] _args = new object[2];
+ _args[0] = channelUri;
+ _args[1] = parameter;
+ System.IAsyncResult _result = base.BeginInvoke("UpdateTile", _args, callback, asyncState);
+ return _result;
+ }
+
+ public void EndUpdateTile(System.IAsyncResult result) {
+ object[] _args = new object[0];
+ base.EndInvoke("UpdateTile", _args, result);
+ }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.svcmap b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.svcmap
new file mode 100644
index 0000000..ebab380
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/Reference.svcmap
@@ -0,0 +1,35 @@
+
+
+
+ true
+ true
+
+ false
+ false
+ false
+
+
+
+
+ false
+ Auto
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Client.Services.ServerInfo1.datasource b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Client.Services.ServerInfo1.datasource
new file mode 100644
index 0000000..1489317
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Client.Services.ServerInfo1.datasource
@@ -0,0 +1,10 @@
+
+
+
+ WindowsPhone.Recipes.Push.Client.Services.ServerInfo, Service References.Services.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Server.Models.xsd b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Server.Models.xsd
new file mode 100644
index 0000000..2cab2fa
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/WindowsPhone.Recipes.Push.Server.Models.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration.svcinfo b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration.svcinfo
new file mode 100644
index 0000000..116b50e
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration.svcinfo
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration91.svcinfo b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration91.svcinfo
new file mode 100644
index 0000000..c01f47f
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/configuration91.svcinfo
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+ BasicHttpBinding_IPushService
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StrongWildcard
+
+
+ 2147483647
+
+
+
+
+
+ 2147483647
+
+
+ Text
+
+
+
+
+
+ System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ System.ServiceModel.Configuration.BasicHttpSecurityElement
+
+
+ None
+
+
+ System.ServiceModel.Configuration.HttpTransportSecurityElement
+
+
+ None
+
+
+ None
+
+
+ System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement
+
+
+ Never
+
+
+ TransportSelected
+
+
+ (Collection)
+
+
+
+
+
+ System.ServiceModel.Configuration.BasicHttpMessageSecurityElement
+
+
+ UserName
+
+
+ Default
+
+
+ System.Text.UTF8Encoding
+
+
+ Buffered
+
+
+
+
+
+
+
+
+
+
+
+ http://localhost:8000/PushService/
+
+
+
+
+
+ basicHttpBinding
+
+
+ BasicHttpBinding_IPushService
+
+
+ Services.IPushService
+
+
+ System.ServiceModel.Configuration.AddressHeaderCollectionElement
+
+
+ <Header />
+
+
+ System.ServiceModel.Configuration.IdentityElement
+
+
+ System.ServiceModel.Configuration.UserPrincipalNameElement
+
+
+
+
+
+ System.ServiceModel.Configuration.ServicePrincipalNameElement
+
+
+
+
+
+ System.ServiceModel.Configuration.DnsElement
+
+
+
+
+
+ System.ServiceModel.Configuration.RsaElement
+
+
+
+
+
+ System.ServiceModel.Configuration.CertificateElement
+
+
+
+
+
+ System.ServiceModel.Configuration.CertificateReferenceElement
+
+
+ My
+
+
+ LocalMachine
+
+
+ FindBySubjectDistinguishedName
+
+
+
+
+
+ False
+
+
+ BasicHttpBinding_IPushService
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.wsdl b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.wsdl
new file mode 100644
index 0000000..df35a51
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.wsdl
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.xsd b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.xsd
new file mode 100644
index 0000000..69527d7
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service.xsd
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service1.xsd b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service1.xsd
new file mode 100644
index 0000000..62ff1db
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Service References/Services/service1.xsd
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ServiceReferences.ClientConfig b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ServiceReferences.ClientConfig
new file mode 100644
index 0000000..504c579
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/ServiceReferences.ClientConfig
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/SplashScreenImage.jpg b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/SplashScreenImage.jpg
new file mode 100644
index 0000000..353b192
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/SplashScreenImage.jpg differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml
new file mode 100644
index 0000000..dfff83b
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml.cs
new file mode 100644
index 0000000..31c1444
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/InboxView.xaml.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO;
+using System.Collections.ObjectModel;
+using System.Threading;
+using Microsoft.Phone.Shell;
+
+using Microsoft.Phone.Notification;
+
+using WindowsPhone.Recipes.Push.Client.Services;
+using WindowsPhone.Recipes.Push.Client.Controls;
+
+namespace WindowsPhone.Recipes.Push.Client.Views
+{
+ public partial class InboxView : UserControl
+ {
+ #region Fields
+
+ /// Url of the GetTileImage REST service.
+ private static readonly string GetTileImageService = App.ServerAddress + "/ImageService/GetTileImage?uri={0}";
+
+ private readonly ObservableCollection _rawMessages = new ObservableCollection();
+ private ShellTileSchedule _tileSchedule;
+
+ #endregion
+
+ #region Properties
+
+ public ObservableCollection RawMessages
+ {
+ get { return _rawMessages; }
+ }
+
+ public IEnumerable ServerImages
+ {
+ get
+ {
+ return new string[]
+ {
+ "number0.png",
+ "number1.png",
+ "number2.png",
+ "number3.png",
+ "number4.png",
+ "number5.png",
+ "number6.png",
+ "number7.png",
+ "number8.png",
+ "number9.png"
+ };
+ }
+ }
+
+
+ public string SelectedServerImage
+ {
+ get { return (string)GetValue(SelectedServerImageProperty); }
+ set { SetValue(SelectedServerImageProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for SelectedServerImage. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty SelectedServerImageProperty =
+ DependencyProperty.Register(
+ "SelectedServerImage",
+ typeof(string),
+ typeof(InboxView),
+ new PropertyMetadata("number0.png"));
+
+
+
+ public IEnumerable PushPatterns
+ {
+ get { return new string[] { "One Time", "Counter", "Ask to Pin", "Custom Tile", "Tile Schedule" }; }
+ }
+
+ public string PushPattern
+ {
+ get { return (string)GetValue(PushPatternProperty); }
+ set { SetValue(PushPatternProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for PushPattern. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty PushPatternProperty =
+ DependencyProperty.Register(
+ "PushPattern",
+ typeof(string),
+ typeof(InboxView),
+ new PropertyMetadata(null, PushPatternChanged));
+
+ private static void PushPatternChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var view = d as InboxView;
+ if ("Tile Schedule".CompareTo(e.NewValue) == 0)
+ {
+ VisualStateManager.GoToState(view, "ScheduleView", false);
+ }
+ else
+ {
+ VisualStateManager.GoToState(view, "NormalView", false);
+ }
+ }
+
+ public int Counter
+ {
+ get { return (int)GetValue(CounterProperty); }
+ set { SetValue(CounterProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for Counter. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty CounterProperty =
+ DependencyProperty.Register(
+ "Counter",
+ typeof(int),
+ typeof(InboxView),
+ new PropertyMetadata(0));
+
+ public string TileScheduleParameter
+ {
+ get { return (string)GetValue(TileScheduleParameterProperty); }
+ set { SetValue(TileScheduleParameterProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for TileScheduleParameter. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty TileScheduleParameterProperty =
+ DependencyProperty.Register(
+ "TileScheduleParameter",
+ typeof(string),
+ typeof(InboxView),
+ new PropertyMetadata("number0.png"));
+
+ #endregion
+
+ public InboxView()
+ {
+ DataContext = this;
+ InitializeComponent();
+
+ Loaded += InboxView_Loaded;
+ Unloaded += InboxView_Unloaded;
+ UpdateServerInfo();
+ }
+
+ private void InboxView_Unloaded(object sender, RoutedEventArgs e)
+ {
+ UnregisterRawNotification();
+ }
+
+ private void InboxView_Loaded(object sender, RoutedEventArgs e)
+ {
+ RegisterRawNotification();
+ }
+
+ private void UpdateServerInfo()
+ {
+ try
+ {
+ var pushService = new PushServiceClient();
+ pushService.GetServerInfoCompleted += (s1, e1) =>
+ {
+ try
+ {
+ pushService.CloseAsync();
+ if (e1.Result != null)
+ {
+ Dispatcher.BeginInvoke(() =>
+ {
+ PushPattern = e1.Result.PushPattern;
+ Counter = e1.Result.Counter;
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.Show();
+ }
+ };
+
+ pushService.GetServerInfoAsync();
+ }
+ catch (Exception ex)
+ {
+ ex.Show();
+ }
+ }
+
+ private void RegisterRawNotification()
+ {
+ var context = PushContext.Current;
+ if (context != null)
+ {
+ context.RawNotification += context_RawNotification;
+ }
+ }
+
+ private void UnregisterRawNotification()
+ {
+ var context = PushContext.Current;
+ if (context != null)
+ {
+ context.RawNotification -= context_RawNotification;
+ }
+ }
+
+ private void context_RawNotification(object sender, HttpNotificationEventArgs e)
+ {
+ try
+ {
+ using (var stream = new StreamReader(e.Notification.Body))
+ {
+ var rawMessage = stream.ReadToEnd();
+ _rawMessages.Insert(0, rawMessage);
+ if ("AskToPin".CompareTo(rawMessage) == 0)
+ {
+ AskToPin();
+ }
+
+ UpdateServerInfo();
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.Show();
+ }
+ }
+
+ private void AskToPin()
+ {
+ NotificationBox.Show("Important", "Please pin your application to Start Screen so this application can work properly.");
+ }
+
+ private void ButtonSchedule_Click(object sender, RoutedEventArgs e)
+ {
+ _tileSchedule = new ShellTileSchedule();
+ _tileSchedule.Recurrence = UpdateRecurrence.Interval;
+ _tileSchedule.StartTime = DateTime.Now;
+ _tileSchedule.Interval = UpdateInterval.EveryHour;
+ _tileSchedule.RemoteImageUri = new Uri(string.Format(GetTileImageService, TileScheduleParameter));
+ _tileSchedule.Start();
+ }
+
+ private void ButtonTestNow_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ var pushService = new PushServiceClient();
+ pushService.UpdateTileCompleted += (s1, e1) =>
+ {
+ try
+ {
+ pushService.CloseAsync();
+ }
+ catch (Exception ex)
+ {
+ ex.Show();
+ }
+ };
+
+ pushService.UpdateTileAsync(PushContext.Current.NotificationChannel.ChannelUri, SelectedServerImage);
+ }
+ catch (Exception ex)
+ {
+ ex.Show();
+ }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/LoginEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/LoginEventArgs.cs
new file mode 100644
index 0000000..ba2c25a
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/LoginEventArgs.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Client.Views
+{
+ public class LoginEventArgs : EventArgs
+ {
+ public Exception Exception { get; private set; }
+
+ public LoginEventArgs(Exception exception = null)
+ {
+ Exception = exception;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml
new file mode 100644
index 0000000..79f6e7d
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml.cs
new file mode 100644
index 0000000..c84c424
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/PushSettingsView.xaml.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace WindowsPhone.Recipes.Push.Client.Views
+{
+ public partial class PushSettingsView : UserControl
+ {
+ public PushSettingsView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml
new file mode 100644
index 0000000..591fe6c
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml.cs
new file mode 100644
index 0000000..0602901
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/Views/UserLoginView.xaml.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+
+using WindowsPhone.Recipes.Push.Client.Services;
+using System.Threading;
+
+namespace WindowsPhone.Recipes.Push.Client.Views
+{
+ public partial class UserLoginView : UserControl
+ {
+ #region Fields
+
+ private readonly IsolatedStorageSettings Settings = IsolatedStorageSettings.ApplicationSettings;
+
+ #endregion
+
+ #region Properties
+
+ public string UserName { get; set; }
+
+ #endregion
+
+ #region Events
+
+ public event EventHandler Login;
+
+ #endregion
+
+ public UserLoginView()
+ {
+ DataContext = this;
+
+ InitializeComponent();
+
+ Loaded += UserLoginView_Loaded;
+ }
+
+ private void UserLoginView_Loaded(object sender, RoutedEventArgs e)
+ {
+ string userName;
+ if (!Settings.TryGetValue("LoginPage.UserName", out userName))
+ {
+ login.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ UserName = userName;
+ InternalLogin();
+ }
+ }
+
+ private void ButtonLogin_Click(object sender, RoutedEventArgs args)
+ {
+ Settings["LoginPage.UserName"] = UserName;
+ login.Visibility = Visibility.Collapsed;
+ InternalLogin();
+ }
+
+ private void OnLogin(LoginEventArgs args)
+ {
+ if (Login != null)
+ {
+ Login(this, args);
+ }
+ }
+
+ private void InternalLogin()
+ {
+ login.Visibility = Visibility.Collapsed;
+ progress.Visibility = Visibility.Visible;
+
+ var pushContext = PushContext.Current;
+ pushContext.Connect(c => RegisterClient(c.ChannelUri));
+ }
+
+ private void RegisterClient(Uri channelUri)
+ {
+ // Register the URI with 3rd party web service.
+ try
+ {
+ var pushService = new PushServiceClient();
+ pushService.RegisterCompleted += (s, e) =>
+ {
+ pushService.CloseAsync();
+
+ Completed(e.Error);
+ };
+
+ pushService.RegisterAsync(UserName, channelUri);
+ }
+ catch (Exception ex)
+ {
+ Completed(ex);
+ }
+ }
+
+ private void Completed(Exception ex)
+ {
+ login.Visibility = Visibility.Visible;
+ progress.Visibility = Visibility.Collapsed;
+
+ Dispatcher.BeginInvoke(() => OnLogin(new LoginEventArgs(ex)));
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/WindowsPhone.Recipes.Push.Client.csproj b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/WindowsPhone.Recipes.Push.Client.csproj
new file mode 100644
index 0000000..dbc2243
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Client/WindowsPhone.Recipes.Push.Client.csproj
@@ -0,0 +1,196 @@
+
+
+
+ Debug
+ AnyCPU
+ 10.0.20506
+ 2.0
+ {DD28493E-0C20-4175-AEB0-E76D94EC92D3}
+ {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ Properties
+ WindowsPhone.Recipes.Push.Client
+ PushClient
+ v4.0
+ $(TargetFrameworkVersion)
+ WindowsPhone
+ Silverlight
+ true
+
+
+ true
+ true
+ PushClient.xap
+ Properties\AppManifest.xml
+ WindowsPhone.Recipes.Push.Client.App
+ true
+ true
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ true
+ full
+ false
+ Bin\Debug
+ DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE
+ true
+ true
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ Bin\Release
+ TRACE;SILVERLIGHT;WINDOWS_PHONE
+ true
+ true
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ App.xaml
+
+
+ NotificationBox.xaml
+
+
+
+
+
+ MainPage.xaml
+
+
+
+ ProgressBarWithText.xaml
+
+
+
+
+
+
+
+ PushSettingsControl.xaml
+
+
+ True
+ True
+ Reference.svcmap
+
+
+ InboxView.xaml
+
+
+
+ PushSettingsView.xaml
+
+
+ UserLoginView.xaml
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+ Reference.svcmap
+
+
+ Designer
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+ WCF Proxy Generator
+ Reference.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ClassDiagram.cd b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ClassDiagram.cd
new file mode 100644
index 0000000..84f5cad
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ClassDiagram.cd
@@ -0,0 +1,139 @@
+
+
+
+
+
+ AAEAAIAAAAAAAAAAAAAAQAAAAAAAAAAAACAAAAAAAAA=
+ Guard.cs
+
+
+
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAEAAAAEAgAQAAAAAAAAAA=
+ HttpWebResponseExtensions.cs
+
+
+
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=
+ MessageSendException.cs
+
+
+
+
+
+
+
+
+
+ FAAAAAAAAQCAAAAgAAACAAAAAAgAAAAAIABAAAAAAAA=
+ MessageSendResult.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PushNotificationMessage.cs
+
+
+
+
+ CBBCAAAAAAIAAIgAAEAQgAAggABAQAAAAAKRAAAAEIA=
+ PushNotificationMessage.cs
+
+
+
+
+
+ AAAAAAAIAAAAAAgAAABAAAAAAAAAQAAAAAACAAAAAAA=
+ RawPushNotificationMessage.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ARAAAAABAIAAAEgAAARACAQCAAAAQAAgAACAAAAAAKA=
+ TilePushNotificationMessage.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ABAAAAAAAIAAAEgAAARAAEAABgAAQAAAAAAAAAAAAKA=
+ ToastPushNotificationMessage.cs
+
+
+
+
+
+ AAAAAAAAACAAAAAAACgBEABAQQAAAAAAAAAAAJACAIA=
+
+
+
+
+
+ ABIACAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ DeviceConnectionStatus.cs
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAgAAAAAAAAgIAAAAAAAAAAAAAAA=
+ MessageSendPriority.cs
+
+
+
+
+
+ AAIAAECBAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAA=
+ NotificationStatus.cs
+
+
+
+
+
+ AAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAhAAAAAAAAAAA=
+ SubscriptionStatus.cs
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/DeviceConnectionStatus.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/DeviceConnectionStatus.cs
new file mode 100644
index 0000000..f362df9
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/DeviceConnectionStatus.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Windows Phone Device connection status.
+ ///
+ public enum DeviceConnectionStatus
+ {
+ /// The request is not applicable.
+ NotApplicable,
+
+ /// The device is connected.
+ Connected,
+
+ /// The device is temporarily disconnected.
+ TempDisconnected,
+
+ /// The device is in an inactive state.
+ Inactive
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Guard.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Guard.cs
new file mode 100644
index 0000000..9e9131d
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Guard.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// A static helper class that includes various parameter checking routines.
+ ///
+ public static partial class Guard
+ {
+ ///
+ /// Throws if the given argument is null.
+ ///
+ /// if tested value if null.
+ /// Argument value to test.
+ /// Name of the argument being tested.
+ public static void ArgumentNotNull(object argumentValue,
+ string argumentName)
+ {
+ if (argumentValue == null)
+ {
+ throw new ArgumentNullException(argumentName);
+ }
+ }
+
+ ///
+ /// Throws an exception if the tested string argument is null or the empty string.
+ ///
+ /// Thrown if string value is null.
+ /// Thrown if the string is empty
+ /// Argument value to check.
+ /// Name of argument being checked.
+ public static void ArgumentNotNullOrEmpty(string argumentValue,
+ string argumentName)
+ {
+ if (argumentValue == null)
+ {
+ throw new ArgumentNullException(argumentName);
+ }
+
+ if (argumentValue.Length == 0)
+ {
+ throw new ArgumentException(Resources.ArgumentMustNotBeEmpty, argumentName);
+ }
+ }
+
+ ///
+ /// Verifies that an argument type is assignable from the provided type (meaning
+ /// interfaces are implemented, or classes exist in the base class hierarchy).
+ ///
+ /// The argument type that will be assigned to.
+ /// The type of the value being assigned.
+ /// Argument name.
+ public static void TypeIsAssignable(Type assignmentTargetType, Type assignmentValueType, string argumentName)
+ {
+ if (assignmentTargetType == null)
+ {
+ throw new ArgumentNullException("assignmentTargetType");
+ }
+
+ if (assignmentValueType == null)
+ {
+ throw new ArgumentNullException("assignmentValueType");
+ }
+
+ if (!assignmentTargetType.IsAssignableFrom(assignmentValueType))
+ {
+ throw new ArgumentException(string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.TypesAreNotAssignable,
+ assignmentTargetType,
+ assignmentValueType),
+ argumentName);
+ }
+ }
+
+ ///
+ /// Verifies that an argument instance is assignable from the provided type (meaning
+ /// interfaces are implemented, or classes exist in the base class hierarchy, or instance can be
+ /// assigned through a runtime wrapper, as is the case for COM Objects).
+ ///
+ /// The argument type that will be assigned to.
+ /// The instance that will be assigned.
+ /// Argument name.
+ [SuppressMessage(
+ "Microsoft.Design",
+ "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "GetType() invoked for diagnostics purposes")]
+ public static void InstanceIsAssignable(Type assignmentTargetType, object assignmentInstance, string argumentName)
+ {
+ if (assignmentTargetType == null)
+ {
+ throw new ArgumentNullException("assignmentTargetType");
+ }
+
+ if (assignmentInstance == null)
+ {
+ throw new ArgumentNullException("assignmentInstance");
+ }
+
+ if (!assignmentTargetType.IsInstanceOfType(assignmentInstance))
+ {
+ throw new ArgumentException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.TypesAreNotAssignable,
+ assignmentTargetType,
+ GetTypeName(assignmentInstance)),
+ argumentName);
+ }
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "Need to use exception as flow control here, no other choice")]
+ private static string GetTypeName(object assignmentInstance)
+ {
+ string assignmentInstanceType;
+ try
+ {
+ assignmentInstanceType = assignmentInstance.GetType().FullName;
+ }
+ catch (Exception)
+ {
+ assignmentInstanceType = Resources.UnknownType;
+ }
+ return assignmentInstanceType;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/HttpWebResponseExtensions.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/HttpWebResponseExtensions.cs
new file mode 100644
index 0000000..d2e852d
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/HttpWebResponseExtensions.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Extends the type with methods for translating push notification specific status codes strings to strong typed enumeration.
+ ///
+ internal static class HttpWebResponseExtensions
+ {
+ ///
+ /// Gets the Notification Status code as enumeration.
+ ///
+ /// The http web response instance.
+ /// Correlate enumeration value.
+ public static NotificationStatus GetNotificationStatus(this HttpWebResponse response)
+ {
+ return response.GetStatus(
+ NotificationStatus.NotApplicable,
+ PushNotificationMessage.Headers.NotificationStatus);
+ }
+
+ ///
+ /// Gets the Device Connection Status code as enumeration.
+ ///
+ /// The http web response instance.
+ /// Correlate enumeration value.
+ public static DeviceConnectionStatus GetDeviceConnectionStatus(this HttpWebResponse response)
+ {
+ return response.GetStatus(
+ DeviceConnectionStatus.NotApplicable,
+ PushNotificationMessage.Headers.DeviceConnectionStatus);
+ }
+
+ ///
+ /// Gets the Subscription Status code as enumeration.
+ ///
+ /// The http web response instance.
+ /// Correlate enumeration value.
+ public static SubscriptionStatus GetSubscriptionStatus(this HttpWebResponse response)
+ {
+ return response.GetStatus(
+ SubscriptionStatus.NotApplicable,
+ PushNotificationMessage.Headers.SubscriptionStatus);
+ }
+
+ private static T GetStatus(this HttpWebResponse response, T def, string header) where T : struct
+ {
+ string statusString = response.Headers[header];
+ T status = def;
+ Enum.TryParse(statusString, out status);
+ return status;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendException.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendException.cs
new file mode 100644
index 0000000..1041a70
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendException.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents errors that occur during push notification message send operation.
+ ///
+ public class MessageSendException : Exception
+ {
+ ///
+ /// Gets the message send result.
+ ///
+ public MessageSendResult Result { get; private set; }
+
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ /// The send operation result.
+ /// An inner exception causes this error.
+ internal MessageSendException(MessageSendResult result, Exception innerException)
+ : base(Resources.FailedToSendMessage, innerException)
+ {
+ Result = result;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendPriority.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendPriority.cs
new file mode 100644
index 0000000..cb183b1
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendPriority.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents the priorities of which the Push Notification Service sends the message.
+ ///
+ public enum MessageSendPriority
+ {
+ /// The message should be delivered by the Push Notification Service immediately.
+ High = 0,
+
+ /// The message should be delivered by the Push Notification Service within 450 seconds.
+ Normal = 1,
+
+ /// The message should be delivered by the Push Notification Service within 900 seconds.
+ Low = 2
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendResult.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendResult.cs
new file mode 100644
index 0000000..5c16cbf
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/MessageSendResult.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.Runtime.Serialization;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Push notification message send operation result.
+ ///
+ public class MessageSendResult
+ {
+ #region Properties
+
+ ///
+ /// Gets the original exception or null.
+ ///
+ public Exception Exception { get; private set; }
+
+ ///
+ /// Gets the response time offset.
+ ///
+ public DateTimeOffset Timestamp { get; private set; }
+
+ ///
+ /// Gets the associated message.
+ ///
+ public PushNotificationMessage AssociatedMessage { get; private set; }
+
+ ///
+ /// Gets the channel URI.
+ ///
+ public Uri ChannelUri { get; private set; }
+
+ ///
+ /// Gets the web request status.
+ ///
+ public HttpStatusCode StatusCode { get; private set; }
+
+ ///
+ /// Gets the push notification status.
+ ///
+ public NotificationStatus NotificationStatus { get; private set; }
+
+ ///
+ /// Gets the device connection status.
+ ///
+ public DeviceConnectionStatus DeviceConnectionStatus { get; private set; }
+
+ ///
+ /// Gets the subscription status.
+ ///
+ public SubscriptionStatus SubscriptionStatus { get; private set; }
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ internal MessageSendResult(PushNotificationMessage associatedMessage, Uri channelUri, WebResponse response)
+ {
+ Timestamp = DateTimeOffset.Now;
+ AssociatedMessage = associatedMessage;
+ ChannelUri = channelUri;
+
+ InitializeStatusCodes(response as HttpWebResponse);
+ }
+
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ internal MessageSendResult(PushNotificationMessage associatedMessage, Uri channelUri, WebException exception)
+ : this(associatedMessage, channelUri, response: exception.Response)
+ {
+ Exception = exception;
+ }
+
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ internal MessageSendResult(PushNotificationMessage associatedMessage, Uri channelUri, Exception exception)
+ : this(associatedMessage, channelUri, response: null)
+ {
+ Exception = exception;
+ }
+
+ #endregion
+
+ #region Privates
+
+ private void InitializeStatusCodes(HttpWebResponse response)
+ {
+ if (response == null)
+ {
+ StatusCode = HttpStatusCode.InternalServerError;
+ NotificationStatus = NotificationStatus.NotApplicable;
+ DeviceConnectionStatus = DeviceConnectionStatus.NotApplicable;
+ SubscriptionStatus = SubscriptionStatus.NotApplicable;
+ }
+ else
+ {
+ StatusCode = response.StatusCode;
+ NotificationStatus = response.GetNotificationStatus();
+ DeviceConnectionStatus = response.GetDeviceConnectionStatus();
+ SubscriptionStatus = response.GetSubscriptionStatus();
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/NotificationStatus.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/NotificationStatus.cs
new file mode 100644
index 0000000..daacca4
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/NotificationStatus.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Microsoft Push Notification Service notification request status.
+ ///
+ public enum NotificationStatus
+ {
+ /// The request is not applicable.
+ NotApplicable,
+
+ /// The notification request was accepted.
+ Received,
+
+ /// Queue overflow. The Push Notification Service should re-send the notification later.
+ QueueFull,
+
+ /// The push notification was suppressed by the Push Notification Service.
+ Suppressed,
+
+ /// The push notification was dropped by the Push Notification Service.
+ Dropped,
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/AssemblyInfo.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..350d64c
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/AssemblyInfo.cs
@@ -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("NotificationSenderUtility")]
+[assembly: AssemblyDescription("Class Library to communicate with the Push Notification Service")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft Corp.")]
+[assembly: AssemblyProduct("Using Push Notifications Hands-on Lab")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[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("4cb73b37-8cd0-456a-8c69-ea3e6622582b")]
+
+// 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")]
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.Designer.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..ae81966
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.Designer.cs
@@ -0,0 +1,135 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WindowsPhone.Recipes.Push.Messasges.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsPhone.Recipes.Push.Messasges.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The provided string argument must not be empty..
+ ///
+ internal static string ArgumentMustNotBeEmpty {
+ get {
+ return ResourceManager.GetString("ArgumentMustNotBeEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Count value {0} is not valid. Count value must not be lower than {1} or greater than {2}..
+ ///
+ internal static string CountValueIsNotValid {
+ get {
+ return ResourceManager.GetString("CountValueIsNotValid", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to send push notification message..
+ ///
+ internal static string FailedToSendMessage {
+ get {
+ return ResourceManager.GetString("FailedToSendMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The provided payload must not be null..
+ ///
+ internal static string PayloadMustNotBeNull {
+ get {
+ return ResourceManager.GetString("PayloadMustNotBeNull", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Payload size is too big. Maximum payload size shouldn't exceed {0} bytes..
+ ///
+ internal static string PayloadSizeIsTooBig {
+ get {
+ return ResourceManager.GetString("PayloadSizeIsTooBig", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Server returned error status code:{0}..
+ ///
+ internal static string ServerErrorStatusCode {
+ get {
+ return ResourceManager.GetString("ServerErrorStatusCode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The type {1} cannot be assigned to variables of type {0}..
+ ///
+ internal static string TypesAreNotAssignable {
+ get {
+ return ResourceManager.GetString("TypesAreNotAssignable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to <unknown>.
+ ///
+ internal static string UnknownType {
+ get {
+ return ResourceManager.GetString("UnknownType", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.resx b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.resx
new file mode 100644
index 0000000..7a3e21d
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/Properties/Resources.resx
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The provided string argument must not be empty.
+
+
+ Count value {0} is not valid. Count value must not be lower than {1} or greater than {2}.
+
+
+ Failed to send push notification message.
+
+
+ The provided payload must not be null.
+
+
+ Payload size is too big. Maximum payload size shouldn't exceed {0} bytes.
+
+
+ Server returned error status code:{0}.
+
+
+ The type {1} cannot be assigned to variables of type {0}.
+
+
+ <unknown>
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/PushNotificationMessage.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/PushNotificationMessage.cs
new file mode 100644
index 0000000..909844e
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/PushNotificationMessage.cs
@@ -0,0 +1,388 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.Diagnostics;
+using System.Threading;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents a base class for push notification messages.
+ ///
+ ///
+ /// This class members are thread safe.
+ ///
+ public abstract class PushNotificationMessage
+ {
+ #region Constants
+
+ /// Push notification maximum message size including headers and payload.
+ protected const int MaxMessageSize = 1024;
+
+ ///
+ /// Well known push notification message web request headers.
+ ///
+ internal static class Headers
+ {
+ public const string MessageId = "X-MessageID";
+ public const string BatchingInterval = "X-NotificationClass";
+ public const string NotificationStatus = "X-NotificationStatus";
+ public const string DeviceConnectionStatus = "X-DeviceConnectionStatus";
+ public const string SubscriptionStatus = "X-SubscriptionStatus";
+ public const string WindowsPhoneTarget = "X-WindowsPhone-Target";
+ }
+
+ #endregion
+
+ #region Fields
+
+ /// Synchronizes payload manipulations.
+ private readonly object _sync = new object();
+
+ /// The payload raw bytes of this message.
+ private byte[] _payload;
+
+ private MessageSendPriority _sendPriority;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets this message unique ID.
+ ///
+ public Guid Id { get; private set; }
+
+ ///
+ /// Gets or sets the send priority of this message in the MPNS.
+ ///
+ public MessageSendPriority SendPriority
+ {
+ get
+ {
+ return _sendPriority;
+ }
+
+ set
+ {
+ SafeSet(ref _sendPriority, value);
+ }
+ }
+
+ ///
+ /// Gets or sets the message payload.
+ ///
+ protected byte[] Payload
+ {
+ get
+ {
+ return _payload;
+ }
+
+ set
+ {
+ SafeSet(ref _payload, value);
+ }
+ }
+
+ protected abstract int NotificationClassId
+ {
+ get;
+ }
+
+ ///
+ /// Gets or sets the flag indicating that one of the message properties
+ /// has changed, thus the payload should be rebuilt.
+ ///
+ private bool IsDirty { get; set; }
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initializes a new instance of this type with send priority.
+ ///
+ protected PushNotificationMessage(MessageSendPriority sendPriority = MessageSendPriority.Normal)
+ {
+ Id = Guid.NewGuid();
+ SendPriority = sendPriority;
+ IsDirty = true;
+ }
+
+ #endregion
+
+ #region Operations
+
+ ///
+ /// Synchronously send this messasge to the destination address.
+ ///
+ ///
+ /// Note that properties of this instance may be changed by different threads while
+ /// sending, but once the payload created, it won't be changed until the next send.
+ ///
+ /// Destination address uri.
+ /// One of the arguments is null.
+ /// Payload size is out of range. For maximum allowed message size see
+ /// Failed to send message for any reason.
+ /// The result instance with relevant information for this send operation.
+ public MessageSendResult Send(Uri uri)
+ {
+ Guard.ArgumentNotNull(uri, "uri");
+
+ // Create payload or reuse cached one.
+ var payload = GetOrCreatePayload();
+
+ // Create and initialize the request object.
+ var request = CreateWebRequest(uri, payload);
+
+ var result = SendSynchronously(payload, uri, request);
+ return result;
+ }
+
+ ///
+ /// Asynchronously send this messasge to the destination address.
+ ///
+ ///
+ /// This method uses the .NET Thread Pool. Use this method to send one or few
+ /// messages asynchronously. If you have many messages to send, please consider
+ /// of using the synchronous method with custom (external) queue-thread solution.
+ ///
+ /// Note that properties of this instance may be changed by different threads while
+ /// sending, but once the payload created, it won't be changed until the next send.
+ ///
+ /// Destination address uri.
+ /// Message sent callback.
+ /// Message send error callback.
+ /// One of the arguments is null.
+ /// Payload size is out of range. For maximum allowed message size see
+ public void SendAsync(Uri uri, Action messageSent = null, Action messageError = null)
+ {
+ Guard.ArgumentNotNull(uri, "uri");
+
+ // Create payload or reuse cached one.
+ var payload = GetOrCreatePayload();
+
+ // Create and initialize the request object.
+ var request = CreateWebRequest(uri, payload);
+
+ SendAsynchronously(
+ payload,
+ uri,
+ request,
+ messageSent ?? (result => { }),
+ messageError ?? (result => { }));
+ }
+
+ #endregion
+
+ #region Protected & Virtuals
+
+ ///
+ /// Override to create the message payload.
+ ///
+ /// The messasge payload bytes.
+ protected virtual byte[] OnCreatePayload()
+ {
+ return _payload;
+ }
+
+ ///
+ /// Override to initialize the message web request with custom headers.
+ ///
+ /// The message web request.
+ protected virtual void OnInitializeRequest(HttpWebRequest request)
+ {
+ }
+
+ ///
+ /// Check the size of the payload and reject it if too big.
+ ///
+ /// Payload raw bytes.
+ protected abstract void VerifyPayloadSize(byte[] payload);
+
+ ///
+ /// Safely set oldValue with newValue in case that are different, and raise the dirty flag.
+ ///
+ /// The type of the value.
+ /// The old value.
+ /// The new value.
+ protected void SafeSet(ref T oldValue, T newValue)
+ {
+ lock (_sync)
+ {
+ if (!object.Equals(oldValue, newValue))
+ {
+ oldValue = newValue;
+ IsDirty = true;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Privates
+
+ ///
+ /// Synchronously send this message to the destination uri.
+ ///
+ /// The message payload bytes.
+ /// The message destination uri.
+ /// Initialized Web request instance.
+ /// The result instance with relevant information for this send operation.
+ private MessageSendResult SendSynchronously(byte[] payload, Uri uri, HttpWebRequest request)
+ {
+ try
+ {
+ // Get the request stream.
+ using (var requestStream = request.GetRequestStream())
+ {
+ // Start to write the payload to the stream.
+ requestStream.Write(payload, 0, payload.Length);
+
+ // Switch to receiving the response from MPNS.
+ using (var response = (HttpWebResponse)request.GetResponse())
+ {
+ var result = new MessageSendResult(this, uri, response);
+ if (response.StatusCode != HttpStatusCode.OK)
+ {
+ throw new InvalidOperationException(string.Format(Resources.ServerErrorStatusCode, response.StatusCode));
+ }
+
+ return result;
+ }
+ }
+ }
+ catch (WebException ex)
+ {
+ var result = new MessageSendResult(this, uri, ex);
+ throw new MessageSendException(result, ex);
+ }
+ catch (Exception ex)
+ {
+ var result = new MessageSendResult(this, uri, ex);
+ throw new MessageSendException(result, ex);
+ }
+ }
+
+ ///
+ /// Asynchronously send this message to the destination uri using the HttpWebRequest context.
+ ///
+ /// The message payload bytes.
+ /// The message destination uri.
+ /// Initialized Web request instance.
+ /// Message sent callback.
+ /// Message send error callback.
+ /// The result instance with relevant information for this send operation.
+ private void SendAsynchronously(byte[] payload, Uri uri, HttpWebRequest request, Action sent, Action error)
+ {
+ try
+ {
+ // Get the request stream asynchronously.
+ request.BeginGetRequestStream(requestAsyncResult =>
+ {
+ try
+ {
+ using (var requestStream = request.EndGetRequestStream(requestAsyncResult))
+ {
+ // Start writing the payload to the stream.
+ requestStream.Write(payload, 0, payload.Length);
+ }
+
+ // Switch to receiving the response from MPNS asynchronously.
+ request.BeginGetResponse(responseAsyncResult =>
+ {
+ try
+ {
+ using (var response = (HttpWebResponse)request.EndGetResponse(responseAsyncResult))
+ {
+ var result = new MessageSendResult(this, uri, response);
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ sent(result);
+ }
+ else
+ {
+ error(result);
+ }
+ }
+ }
+ catch (Exception ex3)
+ {
+ error(new MessageSendResult(this, uri, ex3));
+ }
+ }, null);
+ }
+ catch (Exception ex2)
+ {
+ error(new MessageSendResult(this, uri, ex2));
+ }
+ }, null);
+ }
+ catch (Exception ex1)
+ {
+ error(new MessageSendResult(this, uri, ex1));
+ }
+ }
+
+ ///
+ /// Create a payload and verify its size.
+ ///
+ /// Payload raw bytes.
+ private byte[] GetOrCreatePayload()
+ {
+ if (IsDirty)
+ {
+ lock (_sync)
+ {
+ if (IsDirty)
+ {
+ var payload = OnCreatePayload() ?? new byte[0];
+ DebugOutput(payload);
+ VerifyPayloadSize(payload);
+
+ _payload = payload;
+
+ IsDirty = false;
+ }
+ }
+ }
+
+ return _payload;
+ }
+
+ private HttpWebRequest CreateWebRequest(Uri uri, byte[] payload)
+ {
+ var request = (HttpWebRequest)WebRequest.Create(uri);
+ request.Method = WebRequestMethods.Http.Post;
+ request.ContentType = "text/xml; charset=utf-8";
+ request.ContentLength = payload.Length;
+ request.Headers[Headers.MessageId] = Id.ToString();
+
+ // Batching interval is composed of the message priority and the message class id.
+ int batchingInterval = ((int)SendPriority * 10) + NotificationClassId;
+ request.Headers[Headers.BatchingInterval] = batchingInterval.ToString();
+
+ OnInitializeRequest(request);
+
+ return request;
+ }
+
+ #endregion
+
+ #region Diagnostics
+
+ [Conditional("DEBUG")]
+ private static void DebugOutput(byte[] payload)
+ {
+ string payloadString = Encoding.ASCII.GetString(payload);
+ Debug.WriteLine(payloadString);
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/RawPushNotificationMessage.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/RawPushNotificationMessage.cs
new file mode 100644
index 0000000..a81b975
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/RawPushNotificationMessage.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents a raw push notification message.
+ ///
+ ///
+ /// If you do not wish to update the tile or send a toast notification, you can instead
+ /// send raw information to your application using a raw notification. If your application
+ /// is not currently running, the raw notification is discarded on the Microsoft Push
+ /// Notification Service and is not delivered to the device.
+ ///
+ /// This class members are thread safe.
+ ///
+ public sealed class RawPushNotificationMessage : PushNotificationMessage
+ {
+ #region Constants
+
+ /// Calculated raw message headers size.
+ /// This should ne updated if changing the protocol.
+ private const int RawMessageHeadersSize = 116;
+
+ /// Raw push notification message maximum payload size.
+ public const int MaxPayloadSize = MaxMessageSize - RawMessageHeadersSize;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the message raw data bytes.
+ ///
+ public byte[] RawData
+ {
+ get
+ {
+ return Payload;
+ }
+
+ set
+ {
+ Payload = value;
+ }
+ }
+
+ ///
+ /// Raw push notification message class id.
+ ///
+ protected override int NotificationClassId
+ {
+ get { return 3; }
+ }
+
+ #endregion
+
+ #region Ctor
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ /// The send priority of this message in the MPNS.
+ public RawPushNotificationMessage(MessageSendPriority sendPriority = MessageSendPriority.Normal)
+ : base(sendPriority)
+ {
+
+ }
+ #endregion
+
+ #region Overrides
+
+ protected override void VerifyPayloadSize(byte[] payload)
+ {
+ if (payload.Length > MaxPayloadSize)
+ {
+ throw new ArgumentOutOfRangeException(string.Format(Resources.PayloadSizeIsTooBig, MaxPayloadSize));
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/SubscriptionStatus.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/SubscriptionStatus.cs
new file mode 100644
index 0000000..da3f555
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/SubscriptionStatus.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Push notification channel subscription status.
+ ///
+ public enum SubscriptionStatus
+ {
+ /// The request is not applicable.
+ NotApplicable,
+
+ /// The subscription is active.
+ Active,
+
+ /// The subscription has expired.
+ Expired
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/TilePushNotificationMessage.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/TilePushNotificationMessage.cs
new file mode 100644
index 0000000..603157e
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/TilePushNotificationMessage.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents a tile push notification message.
+ ///
+ ///
+ /// Every phone application has one assigned 'tile' – a visual, dynamic
+ /// representation of the application or its content. A tile displays in
+ /// the Start screen if the end user has pinned it.
+ ///
+ /// This class members are thread safe.
+ ///
+ public sealed class TilePushNotificationMessage : PushNotificationMessage
+ {
+ #region Constants
+
+ /// Calculated tile message headers size.
+ /// This should ne updated if changing the protocol.
+ private const int TileMessageHeadersSize = 146;
+
+ /// Tile push notification message maximum payload size.
+ public const int MaxPayloadSize = MaxMessageSize - TileMessageHeadersSize;
+
+ /// The minimum value.
+ public const int MinCount = 0;
+
+ /// The maximum value.
+ public const int MaxCount = 99;
+
+ /// Windows phone target.
+ private const string WindowsPhoneTarget = "token";
+
+ /// A well formed structure of the tile notification message.
+ private const string PayloadString =
+ "" +
+ "" +
+ "" +
+ "{0}" +
+ "{1}" +
+ "{2}" +
+ "" +
+ "";
+
+ #endregion
+
+ #region Fields
+
+ /// The phone's local path, or a remote path for the background image.
+ private Uri _backgroundImageUri;
+
+ /// An integer value to be displayed in the tile.
+ private int _count = MinCount;
+
+ /// The title text should be displayed in the tile.
+ private string _title;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the phone's local path, or a remote path for the background image.
+ ///
+ ///
+ /// If the uri references a remote resource, the maximum allowed size of the tile
+ /// image is 80 KB, with a maximum download time of 15 seconds.
+ ///
+ public Uri BackgroundImageUri
+ {
+ get
+ {
+ return _backgroundImageUri;
+ }
+
+ set
+ {
+ SafeSet(ref _backgroundImageUri, value);
+ }
+ }
+
+ ///
+ /// Gets or sets an integer value from 1 to 99 to be displayed in the tile, or 0 to clear count.
+ ///
+ public int Count
+ {
+ get
+ {
+ return _count;
+ }
+
+ set
+ {
+ if (value < MinCount || value > MaxCount)
+ {
+ throw new ArgumentOutOfRangeException(string.Format(Resources.CountValueIsNotValid, value, MinCount, MaxCount));
+ }
+
+ SafeSet(ref _count, value);
+ }
+ }
+
+ ///
+ /// Gets or sets the title text should be displayed in the tile. Null keeps the existing title.
+ ///
+ ///
+ /// The Title must fit a single line of text and should not be wider than the actual tile.
+ /// Imperatively a good number of letters would be 18-20 characters long.
+ ///
+ public string Title
+ {
+ get
+ {
+ return _title;
+ }
+
+ set
+ {
+ SafeSet(ref _title, value);
+ }
+ }
+
+ ///
+ /// Tile push notification message class id.
+ ///
+ protected override int NotificationClassId
+ {
+ get { return 1; }
+ }
+
+ #endregion
+
+ #region Ctor
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ /// The send priority of this message in the MPNS.
+ public TilePushNotificationMessage(MessageSendPriority sendPriority = MessageSendPriority.Normal)
+ : base(sendPriority)
+ {
+
+ }
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Create the tile message payload.
+ ///
+ /// The message payload bytes.
+ protected override byte[] OnCreatePayload()
+ {
+ var payloadString = string.Format(PayloadString, BackgroundImageUri, Count, Title);
+ return Encoding.ASCII.GetBytes(payloadString);
+ }
+
+ ///
+ /// Initialize the request with tile specific headers.
+ ///
+ /// The message request.
+ protected override void OnInitializeRequest(System.Net.HttpWebRequest request)
+ {
+ request.Headers[Headers.WindowsPhoneTarget] = WindowsPhoneTarget;
+ }
+
+ protected override void VerifyPayloadSize(byte[] payload)
+ {
+ if (payload.Length > MaxPayloadSize)
+ {
+ throw new ArgumentOutOfRangeException(string.Format(Resources.PayloadSizeIsTooBig, MaxPayloadSize));
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ToastPushNotificationMessage.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ToastPushNotificationMessage.cs
new file mode 100644
index 0000000..db1f1b7
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/ToastPushNotificationMessage.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+using WindowsPhone.Recipes.Push.Messasges.Properties;
+
+namespace WindowsPhone.Recipes.Push.Messasges
+{
+ ///
+ /// Represents a toast push notification message.
+ ///
+ ///
+ /// Toast notifications are system-wide notifications that do not disrupt
+ /// the user workflow or require intervention to resolve. They are displayed
+ /// at the top of the screen for ten seconds before disappearing. If the toast
+ /// notification is tapped, the application that sent the toast notification
+ /// will launch. A toast notification can be dismissed with a flick.
+ ///
+ /// This class members are thread safe.
+ ///
+ public sealed class ToastPushNotificationMessage : PushNotificationMessage
+ {
+ #region Constants
+
+ /// Calculated toast message headers size.
+ /// This should ne updated if changing the protocol.
+ private const int ToastMessageHeadersSize = 146;
+
+ /// Toast push notification message maximum payload size.
+ public const int MaxPayloadSize = MaxMessageSize - ToastMessageHeadersSize;
+
+ /// Windows phone target.
+ private const string WindowsPhoneTarget = "toast";
+
+ /// A well formed structure of the toast notification message.
+ private const string PayloadString =
+ "" +
+ "" +
+ "" +
+ "{0}" +
+ "{1}" +
+ "" +
+ "";
+
+ #endregion
+
+ #region Fields
+
+ /// The bolded string that should be displayed immediately after the application icon.
+ private string _title;
+
+ /// The non-bolded string that should be displayed immediately after the Title.
+ private string _subTitle;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets a bolded string that should be displayed immediately after the application icon.
+ ///
+ public string Title
+ {
+ get
+ {
+ return _title;
+ }
+
+ set
+ {
+ SafeSet(ref _title, value);
+ }
+ }
+
+ ///
+ /// Gets or sets a non-bolded string that should be displayed immediately after the Title.
+ ///
+ public string SubTitle
+ {
+ get
+ {
+ return _subTitle;
+ }
+
+ set
+ {
+ SafeSet(ref _subTitle, value);
+ }
+ }
+
+ ///
+ /// Toast push notification message class id.
+ ///
+ protected override int NotificationClassId
+ {
+ get { return 2; }
+ }
+
+ #endregion
+
+ #region Ctor
+ ///
+ /// Initializes a new instance of this type.
+ ///
+ /// The send priority of this message in the MPNS.
+ public ToastPushNotificationMessage(MessageSendPriority sendPriority = MessageSendPriority.Normal)
+ : base(sendPriority)
+ {
+
+ }
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Create the toast message payload.
+ ///
+ /// The message payload bytes.
+ protected override byte[] OnCreatePayload()
+ {
+ var payloadString = string.Format(PayloadString, Title, SubTitle);
+ return Encoding.ASCII.GetBytes(payloadString);
+ }
+
+ ///
+ /// Initialize the request with toast specific headers.
+ ///
+ /// The message request.
+ protected override void OnInitializeRequest(HttpWebRequest request)
+ {
+ request.Headers[Headers.WindowsPhoneTarget] = WindowsPhoneTarget;
+ }
+
+ protected override void VerifyPayloadSize(byte[] payload)
+ {
+ if (payload.Length > MaxPayloadSize)
+ {
+ throw new ArgumentOutOfRangeException(string.Format(Resources.PayloadSizeIsTooBig, MaxPayloadSize));
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/WindowsPhone.Recipes.Push.Messasges.csproj b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/WindowsPhone.Recipes.Push.Messasges.csproj
new file mode 100644
index 0000000..81461d6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Messasges/WindowsPhone.Recipes.Push.Messasges.csproj
@@ -0,0 +1,84 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {E4691236-9F54-4250-BDBE-916BBB07A378}
+ Library
+ Properties
+ WindowsPhone.Recipes.Push.Messasges
+ WindowsPhone.Recipes.Push.Messasges
+ v4.0
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.config b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.config
new file mode 100644
index 0000000..4d45df6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.config
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml
new file mode 100644
index 0000000..c985e17
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml.cs
new file mode 100644
index 0000000..7f9a056
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/App.xaml.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Windows;
+using System.ComponentModel.Composition;
+using System.ComponentModel.Composition.Hosting;
+
+using WindowsPhone.Recipes.Push.Server.Services;
+using WindowsPhone.Recipes.Push.Server.ViewModels;
+
+namespace WindowsPhone.Recipes.Push.Server
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ public CompositionContainer Container { get; private set; }
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ // Initialize MEF to export parts from current assembly.
+ var catalog = new AssemblyCatalog(typeof(App).Assembly);
+ Container = new CompositionContainer(catalog);
+ Container.ComposeParts();
+
+ // Create and show the main window where MainViewModel is the default source for data-binding.
+ new MainWindow
+ {
+ DataContext = Container.GetExportedValue()
+
+ }.Show();
+
+ base.OnStartup(e);
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/IVisualHost.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/IVisualHost.cs
new file mode 100644
index 0000000..b28b6a6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/IVisualHost.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace WindowsPhone.Recipes.Push.Server.Behaviors
+{
+ public interface IVisualHost
+ {
+ Visual Visual { get; set; }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/VisualBinderBehavior.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/VisualBinderBehavior.cs
new file mode 100644
index 0000000..ed12fcd
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Behaviors/VisualBinderBehavior.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Interactivity;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.IO;
+
+namespace WindowsPhone.Recipes.Push.Server.Behaviors
+{
+ ///
+ /// An attached behavior that handle a visual element from the visual tree to associated view-model implementing the interface.
+ ///
+ public class VisualBinderBehavior : Behavior
+ {
+ private IVisualHost _visualHost;
+
+ protected override void OnAttached()
+ {
+ _visualHost = FindVisualHost();
+ if (_visualHost == null)
+ {
+ throw new InvalidOperationException("Visual host wasn't found in the data context hierarchy.");
+ }
+
+ _visualHost.Visual = AssociatedObject;
+
+ base.OnAttached();
+ }
+
+ protected override void OnDetaching()
+ {
+ _visualHost.Visual = null;
+
+ base.OnDetaching();
+ }
+
+ private IVisualHost FindVisualHost()
+ {
+ DependencyObject targetObject = AssociatedObject;
+ IVisualHost visualHost = AssociatedObject.DataContext as IVisualHost;
+ while (targetObject != null)
+ {
+ if (visualHost != null)
+ {
+ return visualHost;
+ }
+
+ targetObject = VisualTreeHelper.GetParent(targetObject);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml
new file mode 100644
index 0000000..ce88b12
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml.cs
new file mode 100644
index 0000000..7d4a127
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/MainWindow.xaml.cs
@@ -0,0 +1,45 @@
+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;
+using System.ServiceModel;
+using System.Windows.Threading;
+using System.ComponentModel.Composition;
+
+using WindowsPhone.Recipes.Push.Server.Services;
+
+namespace WindowsPhone.Recipes.Push.Server
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
+ {
+ // Drag window from anywhere.
+ DragMove();
+
+ base.OnMouseLeftButtonDown(e);
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ Application.Current.Shutdown();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/MessageStatus.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/MessageStatus.cs
new file mode 100644
index 0000000..233b9c7
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/MessageStatus.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.Models
+{
+ ///
+ /// Represents a push notification message send response status.
+ ///
+ public class MessageStatus
+ {
+ private static readonly Dictionary MessageTypes = new Dictionary
+ {
+ {typeof(TilePushNotificationMessage), "Tile"},
+ {typeof(ToastPushNotificationMessage), "Toast"},
+ {typeof(RawPushNotificationMessage), "Raw"}
+ };
+
+ ///
+ /// Gets the push notification pattern type.
+ ///
+ public string Pattern { get; private set; }
+
+ ///
+ /// Gets the response time stamp.
+ ///
+ public DateTimeOffset Timestamp { get; private set; }
+
+ ///
+ /// Gets the message type.
+ ///
+ public string MessageType { get; private set; }
+
+ ///
+ /// Gets the message ID.
+ ///
+ public Guid MessageId { get; private set; }
+
+ ///
+ /// Gets the notification channel URI.
+ ///
+ public Uri ChannelUri { get; private set; }
+
+ ///
+ /// Gets the response status code.
+ ///
+ public HttpStatusCode StatusCode { get; private set; }
+
+ ///
+ /// Gets the notification status.
+ ///
+ public NotificationStatus NotificationStatus { get; private set; }
+
+ ///
+ /// Gets the device connection status.
+ ///
+ public DeviceConnectionStatus DeviceConnectionStatus { get; private set; }
+
+ ///
+ /// Gets the subscription status.
+ ///
+ public SubscriptionStatus SubscriptionStatus { get; private set; }
+
+ ///
+ /// Initialize a new instance of this type.
+ ///
+ public MessageStatus(string pattern, MessageSendResult result)
+ {
+ Pattern = pattern;
+ Timestamp = result.Timestamp;
+ MessageType = MessageTypes[result.AssociatedMessage.GetType()];
+ MessageId = result.AssociatedMessage.Id;
+ ChannelUri = result.ChannelUri;
+ StatusCode = result.StatusCode;
+ NotificationStatus = result.NotificationStatus;
+ DeviceConnectionStatus = result.DeviceConnectionStatus;
+ SubscriptionStatus = result.SubscriptionStatus;
+ }
+
+ ///
+ /// Initialize a new instance of this type.
+ ///
+ public MessageStatus(PushPatternType pattern, MessageSendException exception)
+ {
+
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/PushPatternType.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/PushPatternType.cs
new file mode 100644
index 0000000..ed1f6f5
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/PushPatternType.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.Serialization;
+
+namespace WindowsPhone.Recipes.Push.Server.Models
+{
+ ///
+ /// Types of server push patterns.
+ ///
+ public enum PushPatternType
+ {
+ /// One time server push pattern.
+ OneTime,
+
+ /// Login counter server push pattern.
+ LoginCounter,
+
+ /// Ask to pin server push pattern.
+ AskToPin,
+
+ /// Custom tile image server push pattern.
+ CustomTileImage,
+
+ /// Tile shedule server push pattern.
+ TileSchedule,
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/ServerInfo.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/ServerInfo.cs
new file mode 100644
index 0000000..972143f
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/ServerInfo.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.Serialization;
+
+namespace WindowsPhone.Recipes.Push.Server.Models
+{
+ ///
+ /// Server status data contract.
+ ///
+ [DataContract]
+ public class ServerInfo
+ {
+ ///
+ /// Current push pattern.
+ ///
+ [DataMember]
+ public string PushPattern { get; set; }
+
+ ///
+ /// Current tile counter value.
+ ///
+ [DataMember]
+ public int Counter { get; set; }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/Subscription.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/Subscription.cs
new file mode 100644
index 0000000..f91f17f
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Models/Subscription.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security;
+
+namespace WindowsPhone.Recipes.Push.Server.Models
+{
+ ///
+ /// Represents user subscription.
+ ///
+ public class Subscription
+ {
+ ///
+ /// Gets the user name.
+ ///
+ public string UserName { get; private set; }
+
+ ///
+ /// Gets the notification channel uri.
+ ///
+ public Uri ChannelUri { get; private set; }
+
+ ///
+ /// Initialize a new instance of this type.
+ ///
+ public Subscription(string userName, Uri channelUri)
+ {
+ UserName = userName;
+ ChannelUri = channelUri;
+ }
+
+ ///
+ /// Initialize a new instance of this type.
+ ///
+ public Subscription(string userName, string channelUri)
+ : this (userName, new Uri(channelUri, UriKind.Absolute))
+ {
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/AssemblyInfo.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7940edf
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/AssemblyInfo.cs
@@ -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("WindowsPhone.Recipes.Push.Server")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("WindowsPhone.Recipes.Push.Server")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[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
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the 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")]
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.Designer.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..d5d30d7
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WindowsPhone.Recipes.Push.Server.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsPhone.Recipes.Push.Server.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.resx b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.Designer.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..0d8931c
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WindowsPhone.Recipes.Push.Server.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;
+ }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.settings b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.settings
new file mode 100644
index 0000000..8f2fd95
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/NullTileImageConverter.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/NullTileImageConverter.cs
new file mode 100644
index 0000000..344a91f
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/NullTileImageConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Data;
+
+namespace WindowsPhone.Recipes.Push.Server.Resources.Converters
+{
+ ///
+ /// Converts null to default tile image.
+ ///
+ public class NullTileImageConverter : IValueConverter
+ {
+ /// Default tile image resource relative path.
+ private static readonly Uri DefaultTileImage = new Uri("/Resources/TileImages/Null.jpg", UriKind.Relative);
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return value ?? DefaultTileImage;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/UserFileImageConverter.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/UserFileImageConverter.cs
new file mode 100644
index 0000000..6c60cad
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/Converters/UserFileImageConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Data;
+using System.IO;
+
+namespace WindowsPhone.Recipes.Push.Server.Resources.Converters
+{
+ ///
+ /// Image file name to image file name with relevant path.
+ ///
+ public class UserFileImageConverter : IValueConverter
+ {
+ /// Default tile image resource relative path.
+ private static readonly Uri DefaultTileImage = new Uri("/Resources/TileImages/Null.jpg", UriKind.Relative);
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ Uri imageUri = DefaultTileImage;
+ string fileName = value as string;
+ if (value != null)
+ {
+ string imageFullPath = Path.Combine(@"Resources\TileImages\Numbers", (string)value);
+ if (File.Exists(imageFullPath))
+ {
+ imageUri = new Uri(@"\" + imageFullPath, UriKind.Relative);
+ }
+ }
+
+ return imageUri;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/AskToPinPushPatternViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/AskToPinPushPatternViewModel.xaml
new file mode 100644
index 0000000..12d66fe
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/AskToPinPushPatternViewModel.xaml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CounterPushPatternViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CounterPushPatternViewModel.xaml
new file mode 100644
index 0000000..cdde7ab
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CounterPushPatternViewModel.xaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CustomTileImagePushPatternViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CustomTileImagePushPatternViewModel.xaml
new file mode 100644
index 0000000..91515f6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/CustomTileImagePushPatternViewModel.xaml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/MessageStatusViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/MessageStatusViewModel.xaml
new file mode 100644
index 0000000..1815dc8
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/MessageStatusViewModel.xaml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/OneTimePushPatternViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/OneTimePushPatternViewModel.xaml
new file mode 100644
index 0000000..54aaee2
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/OneTimePushPatternViewModel.xaml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/TileSchedulePushPatternViewModel.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/TileSchedulePushPatternViewModel.xaml
new file mode 100644
index 0000000..9167321
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DataTemplates/TileSchedulePushPatternViewModel.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DefaultSkin.xaml b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DefaultSkin.xaml
new file mode 100644
index 0000000..a486407
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/DefaultSkin.xaml
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Null.jpg b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Null.jpg
new file mode 100644
index 0000000..39e13cb
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Null.jpg differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number0.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number0.png
new file mode 100644
index 0000000..57de9e1
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number0.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number1.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number1.png
new file mode 100644
index 0000000..ef9daf1
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number1.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number2.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number2.png
new file mode 100644
index 0000000..72f178d
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number2.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number3.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number3.png
new file mode 100644
index 0000000..0586364
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number3.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number4.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number4.png
new file mode 100644
index 0000000..80cdb61
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number4.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number5.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number5.png
new file mode 100644
index 0000000..2151c99
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number5.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number6.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number6.png
new file mode 100644
index 0000000..1af6c58
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number6.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number7.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number7.png
new file mode 100644
index 0000000..a03e152
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number7.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number8.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number8.png
new file mode 100644
index 0000000..1d20b49
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number8.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number9.png b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number9.png
new file mode 100644
index 0000000..949974d
Binary files /dev/null and b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Resources/TileImages/Numbers/number9.png differ
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IImageService.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IImageService.cs
new file mode 100644
index 0000000..410f297
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IImageService.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel;
+using System.Text;
+using System.IO;
+using System.ServiceModel.Web;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Provides custom tile images.
+ ///
+ [ServiceContract]
+ public interface IImageService
+ {
+ ///
+ /// Get custom tile image.
+ ///
+ /// The tile image request parameter.
+ /// Custom tile image stream.
+ [OperationContract, WebGet]
+ Stream GetTileImage(string parameter);
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IPushService.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IPushService.cs
new file mode 100644
index 0000000..0da9037
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/IPushService.cs
@@ -0,0 +1,39 @@
+using System.IO;
+using System.ServiceModel;
+using System.ServiceModel.Web;
+using System.Xml.Linq;
+using System;
+
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Push server services.
+ ///
+ [ServiceContract]
+ public interface IPushService
+ {
+ ///
+ /// Register user name with a push channel uri.
+ ///
+ /// User name.
+ /// Push notification channel uri.
+ [OperationContract]
+ void Register(string userName, Uri channelUri);
+
+ ///
+ /// Get current server information/status.
+ ///
+ /// Current server status.
+ [OperationContract]
+ ServerInfo GetServerInfo();
+
+ ///
+ /// Send a tile update with given parameter.
+ ///
+ /// User parameter to send with the tile update request.
+ [OperationContract]
+ void UpdateTile(Uri channelUri, string parameter);
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageRequestEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageRequestEventArgs.cs
new file mode 100644
index 0000000..3e4c33f
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageRequestEventArgs.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Image request event arguments.
+ ///
+ internal class ImageRequestEventArgs : EventArgs
+ {
+ ///
+ /// Tile image maximum size in bytes.
+ ///
+ public const int MaxTileImageSize = 80 * 1024; // The max tile image size is 80k.
+
+ public string Parameter { get; private set; }
+ public Stream ImageStream { get; private set; }
+
+ ///
+ /// Initializes a new instance with a memory stream maximum size of .
+ ///
+ public ImageRequestEventArgs(string parameter)
+ {
+ Parameter = parameter;
+ ImageStream = new MemoryStream(MaxTileImageSize);
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageService.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageService.cs
new file mode 100644
index 0000000..6ed493b
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ImageService.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.IO;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Represents a tile image REST service.
+ ///
+ [Export, PartCreationPolicy(CreationPolicy.Shared), ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
+ internal class ImageService : IImageService
+ {
+ #region Constants
+
+ /// Url of the GetTileImage REST service.
+ public const string GetTileImageService = "http://localhost:8000/ImageService/GetTileImage?parameter={0}";
+
+ #endregion
+
+ #region Fields
+
+ private ServiceHost _serviceHost;
+
+ #endregion
+
+ #region Events
+
+ ///
+ /// Raise when dynamic image creation is requested.
+ ///
+ public event EventHandler ImageRequest;
+
+ #endregion
+
+ #region Operations
+
+ ///
+ /// Host this service using WCF.
+ ///
+ public void Host()
+ {
+ _serviceHost = new ServiceHost(this);
+ _serviceHost.Open();
+ }
+
+ ///
+ /// Get a generated custom tile image stream for the given uri.
+ ///
+ /// The tile image request parameter.
+ /// A stream of the custom tile image generated.
+ public Stream GetTileImage(string parameter)
+ {
+ if (ImageRequest != null)
+ {
+ var args = new ImageRequestEventArgs(parameter);
+ ImageRequest(this, args);
+
+ // Seek the stream back to the begining just in case.
+ args.ImageStream.Seek(0, SeekOrigin.Begin);
+
+ return args.ImageStream;
+ }
+
+ return Stream.Null;
+ }
+ #endregion
+
+ #region Privates Logic
+
+ private void OnImageRequest(ImageRequestEventArgs args)
+ {
+ if (ImageRequest != null)
+ {
+ ImageRequest(this, args);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/PushService.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/PushService.cs
new file mode 100644
index 0000000..8802ae0
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/PushService.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.ServiceModel;
+using System.ComponentModel.Composition;
+
+using WindowsPhone.Recipes.Push.Server.Models;
+using System.Xml.Linq;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Current push server services implementation.
+ ///
+ [Export, PartCreationPolicy(CreationPolicy.Shared), ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
+ internal class PushService : IPushService
+ {
+ #region Fields
+
+ private ServiceHost _serviceHost;
+
+ /// Dictionary contains users subscription objects.
+ private readonly Dictionary _subscribers = new Dictionary();
+
+ /// Sync access to the subscribers dictionary.
+ private readonly object SubscribersSync = new object();
+
+ #endregion
+
+ #region Events
+
+ ///
+ /// Raise when user subscribed.
+ ///
+ public event EventHandler Subscribed;
+
+ ///
+ /// Raise when current server status is requested.
+ ///
+ public event EventHandler GetInfo;
+
+ ///
+ /// Raise when user requests a tile update.
+ ///
+ public event EventHandler TileUpdateRequest;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Get subscription list.
+ ///
+ public IEnumerable Subscribers
+ {
+ get
+ {
+ lock (_subscribers)
+ {
+ var subscribers = new Subscription[_subscribers.Count];
+ _subscribers.Values.CopyTo(subscribers, 0);
+ return subscribers;
+ }
+ }
+ }
+
+ ///
+ /// Get subscription count.
+ ///
+ public int SubscribersCount
+ {
+ get
+ {
+ lock (_subscribers)
+ {
+ return _subscribers.Count;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Operations
+
+ ///
+ /// Register user with notification channel uri.
+ ///
+ /// The user name to register.
+ /// The notification channel uri.
+ public void Register(string userName, Uri channelUri)
+ {
+ if (string.IsNullOrEmpty(userName))
+ {
+ throw new ArgumentException("Invalid user name", "userName");
+ }
+
+ if (channelUri == null)
+ {
+ throw new ArgumentNullException("channelUri");
+ }
+
+ var subscription = new Subscription(userName, channelUri);
+
+ lock (SubscribersSync)
+ {
+ // Add or update existing.
+ _subscribers[userName] = subscription;
+ }
+
+ OnSubscribed(new SubscriptionEventArgs(subscription));
+ }
+
+ ///
+ /// Gets current server info.
+ ///
+ /// An instance info object contains server status.
+ public ServerInfo GetServerInfo()
+ {
+ var args = new ServerInfoEventArgs();
+ OnGetInfo(args);
+ return args.ServerInfo;
+ }
+
+ ///
+ /// Send a tile update with given parameter.
+ ///
+ /// An instance info object contains server status.
+ /// User parameter to send with the tile update request.
+ public void UpdateTile(Uri channelUri, string parameter)
+ {
+ OnTileUpdateRequest(new TileUpdateRequestEventArgs(channelUri, parameter));
+ }
+
+ internal Subscription TryGetSubscription(string userName)
+ {
+ lock (SubscribersSync)
+ {
+ Subscription subscription;
+ if (!_subscribers.TryGetValue(userName, out subscription))
+ {
+ subscription = null;
+ }
+
+ return subscription;
+ }
+ }
+
+ #endregion
+
+ #region Privates Logic
+
+ public void Host()
+ {
+ _serviceHost = new ServiceHost(this);
+ _serviceHost.Open();
+ }
+
+ private void OnSubscribed(SubscriptionEventArgs args)
+ {
+ if (Subscribed != null)
+ {
+ Subscribed(this, args);
+ }
+ }
+
+ private void OnGetInfo(ServerInfoEventArgs args)
+ {
+ if (GetInfo != null)
+ {
+ GetInfo(this, args);
+ }
+ }
+
+ private void OnTileUpdateRequest(TileUpdateRequestEventArgs args)
+ {
+ if (TileUpdateRequest != null)
+ {
+ TileUpdateRequest(this, args);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ServerInfoEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ServerInfoEventArgs.cs
new file mode 100644
index 0000000..3a17c94
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/ServerInfoEventArgs.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Server info event arguments.
+ ///
+ internal class ServerInfoEventArgs : EventArgs
+ {
+ ///
+ /// Gets or sets the server info.
+ ///
+ public ServerInfo ServerInfo { get; set; }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/SubscriptionEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/SubscriptionEventArgs.cs
new file mode 100644
index 0000000..6acbf94
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/SubscriptionEventArgs.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Subscription event arguments.
+ ///
+ internal class SubscriptionEventArgs : EventArgs
+ {
+ public Subscription Subscription { get; private set; }
+
+ public SubscriptionEventArgs(Subscription subscription)
+ {
+ Subscription = subscription;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/TileUpdateRequestEventArgs.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/TileUpdateRequestEventArgs.cs
new file mode 100644
index 0000000..fdcbc56
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/Services/TileUpdateRequestEventArgs.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WindowsPhone.Recipes.Push.Server.Services
+{
+ ///
+ /// Tile update request event arguments.
+ ///
+ internal class TileUpdateRequestEventArgs : EventArgs
+ {
+ public Uri ChannelUri { get; private set; }
+
+ public string Parameter { get; private set; }
+
+ public TileUpdateRequestEventArgs(Uri channelUri, string parameter)
+ {
+ this.ChannelUri = channelUri;
+ this.Parameter = parameter;
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/IMessageSendResultLogger.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/IMessageSendResultLogger.cs
new file mode 100644
index 0000000..efff4d3
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/IMessageSendResultLogger.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Implement this interface to log push notification messages send result and error.
+ ///
+ internal interface IMessageSendResultLogger
+ {
+ ///
+ /// Implement this method by logging push notification messages send result.
+ ///
+ /// The server push pattern used while reporting this message send result.
+ /// The message send result to log.
+ void Log(string patternName, MessageSendResult result);
+
+ ///
+ /// Implement this method by logging push notification messages error result.
+ ///
+ /// The server push pattern used while reporting this message send error.
+ /// The message send result to log.
+ void Log(string patternName, MessageSendException exception);
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MainViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000..21ac39b
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MainViewModel.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.ObjectModel;
+using System.ComponentModel.Composition;
+using System.ServiceModel;
+
+using WindowsPhone.Recipes.Push.Server.Services;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ [Export, PartCreationPolicy(CreationPolicy.Shared)]
+ internal class MainViewModel : ViewModelBase
+ {
+ private PushService _pushService;
+ private ImageService _imageService;
+ private PushPatternViewModel _activePattern;
+
+ [ImportingConstructor]
+ public MainViewModel([ImportMany(typeof(PushPatternViewModel))] IEnumerable pushPatterns)
+ {
+ PushPatterns = pushPatterns;
+ ActivePattern = pushPatterns.FirstOrDefault();
+ }
+
+ [Import]
+ private PushService PushService
+ {
+ get { return _pushService; }
+ set
+ {
+ _pushService = value;
+ _pushService.Subscribed += (s, e) => NotifyPropertyChanged("Subscribers");
+ _pushService.Host();
+ }
+ }
+
+ [Import]
+ private ImageService ImageService
+ {
+ get { return _imageService; }
+ set
+ {
+ _imageService = value;
+ _imageService.Host();
+ }
+ }
+
+ public IEnumerable PushPatterns { get; private set; }
+
+ [Import]
+ public MessageStatusViewModel MessageStatus { get; private set; }
+
+ public PushPatternViewModel ActivePattern
+ {
+ get { return _activePattern; }
+
+ set
+ {
+ if (_activePattern != value)
+ {
+ if (_activePattern != null)
+ {
+ // Deactivate old pattern.
+ _activePattern.IsActive = false;
+ }
+
+ _activePattern = value;
+ if (_activePattern != null)
+ {
+ // Activate new pattern.
+ _activePattern.IsActive = true;
+ }
+
+ NotifyPropertyChanged("ActivePattern");
+ }
+ }
+ }
+
+ public int Subscribers
+ {
+ get { return PushService.SubscribersCount; }
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MessageStatusViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MessageStatusViewModel.cs
new file mode 100644
index 0000000..38eae3c
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/MessageStatusViewModel.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.ObjectModel;
+using System.Windows.Threading;
+using System.ComponentModel.Composition;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ [Export, Export(typeof(IMessageSendResultLogger)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal class MessageStatusViewModel : ViewModelBase, IMessageSendResultLogger
+ {
+ private readonly ObservableCollection _status = new ObservableCollection();
+
+ public ObservableCollection Status
+ {
+ get { return _status; }
+ }
+
+ void IMessageSendResultLogger.Log(string patternName, MessageSendResult result)
+ {
+ Dispatcher.BeginInvoke(() => Status.Add(new MessageStatus(patternName, result)));
+ }
+
+ void IMessageSendResultLogger.Log(string patternName, MessageSendException exception)
+ {
+ Dispatcher.BeginInvoke(() => Status.Add(new MessageStatus(patternName, exception.Result)));
+ }
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/AskToPinPushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/AskToPinPushPatternViewModel.cs
new file mode 100644
index 0000000..9d15e8b
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/AskToPinPushPatternViewModel.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Input;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Services;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents the Ask user to Pin the application push notification pattern.
+ ///
+ ///
+ /// Only users can pin a Windows Phone application to the Start screen, therefore if a given
+ /// application wants to use the tile functionality and the user didn’t pinned
+ /// the app’s tile, we want to notify the user she is missing additional functionality.
+ /// This pattern is implemented in both client and server-side.
+ ///
+ [Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class AskToPinPushPatternViewModel : PushPatternViewModel
+ {
+ #region Fields
+
+ /// A dictionary for tracking tile messages.
+ private readonly Dictionary _messages = new Dictionary();
+
+ /// Synchronizes access to the messages collection.
+ private readonly object MessageSync = new object();
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initialize new instance of this type with defaults.
+ ///
+ public AskToPinPushPatternViewModel()
+ {
+ InitializeDefaults();
+ }
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Send a tile notification to all relevant subscribers.
+ ///
+ protected override void OnSend()
+ {
+ // Asynchronously try to send this message to all relevant subscribers.
+ foreach (var subscriber in PushService.Subscribers)
+ {
+ // Create a tile message to send an update.
+ var tileMsg = GetOrCreateMessage(subscriber.UserName);
+
+ tileMsg.SendAsync(
+ subscriber.ChannelUri,
+ result =>
+ {
+ Log(result);
+ OnMessageSent(subscriber.UserName, result);
+ },
+ Log);
+ }
+ }
+
+ ///
+ /// Once an application is activated again (the client side phone application
+ /// has subscription logic on startup), try to update the tile again.
+ /// In case that the application is not pinned, send raw notification message
+ /// to the client, asking to pin the application. This raw notification message
+ /// has to be well-known and handled by the client side phone application.
+ /// In our case the raw message is AskToPin.
+ ///
+ protected override void OnSubscribed(SubscriptionEventArgs args)
+ {
+ // Asynchronously try to send Tile message to the relevant subscriber
+ // with data already sent before so the tile won't change.
+ var tileMsg = GetOrCreateMessage(args.Subscription.UserName, false);
+
+ tileMsg.SendAsync(
+ args.Subscription.ChannelUri,
+ result =>
+ {
+ Log(result);
+ OnMessageSent(args.Subscription.UserName, result);
+ },
+ Log);
+ }
+
+ #endregion
+
+ #region Privates
+
+ ///
+ /// Once tile update sent, check if handled by the phone.
+ /// In case that the application is not pinned, ask to pin.
+ ///
+ private void OnMessageSent(string userName, MessageSendResult result)
+ {
+ if (!CheckIfPinned(result))
+ {
+ AskUserToPin(result.ChannelUri);
+ }
+ }
+
+ ///
+ /// Just in case that the application is running, send a raw message, asking
+ /// the user to pin the application. This raw message has to be handled in client side.
+ ///
+ private void AskUserToPin(Uri uri)
+ {
+ new RawPushNotificationMessage(MessageSendPriority.High)
+ {
+ RawData = Encoding.ASCII.GetBytes(RawMessage)
+
+ }.SendAsync(uri, Log, Log);
+ }
+
+ private bool CheckIfPinned(MessageSendResult result)
+ {
+ // We known if the application is pinned by checking the following send result flags:
+ return result.DeviceConnectionStatus == DeviceConnectionStatus.Connected &&
+ result.SubscriptionStatus == SubscriptionStatus.Active &&
+ result.NotificationStatus == NotificationStatus.Received;
+ }
+
+ private TilePushNotificationMessage GetOrCreateMessage(string userName, bool overrideExisting = true)
+ {
+ lock (MessageSync)
+ {
+ TilePushNotificationMessage message;
+ if (!_messages.TryGetValue(userName, out message) || overrideExisting)
+ {
+ message = new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ BackgroundImageUri = BackgroundImageUri,
+ Count = Count,
+ Title = Title
+ };
+
+ _messages[userName] = message;
+ }
+
+ return message;
+ }
+ }
+
+ private void InitializeDefaults()
+ {
+ DisplayName = "Ask to Pin";
+ Description = "Only users can pin a Windows Phone application to the Start screen, therefore if a given application wants to use the tile functionality and the user didn’t pinned the app’s tile, we want to notify the user she is missing additional functionality. This pattern is implemented in both client and server-side.";
+ BackgroundImageUri = TileImages.Length > 2 ? TileImages[2] : TileImages.FirstOrDefault();
+ Count = 1;
+ Title = "Game Update";
+ RawMessage = "AskToPin";
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CounterPushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CounterPushPatternViewModel.cs
new file mode 100644
index 0000000..b5d58c6
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CounterPushPatternViewModel.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Xml.Linq;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Services;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents the Counter push notification pattern.
+ ///
+ ///
+ /// Send a tile push notification message with a counter value.
+ /// Each time a push notification message is sent the counter value
+ /// increases by one, unless user is running the application and notifies
+ /// the server.
+ ///
+ [Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class CounterPushPatternViewModel : PushPatternViewModel
+ {
+ #region Fields
+
+ /// A dictionary for tracking tile message count while phone-application is not running.
+ private readonly Dictionary _messageCounter = new Dictionary();
+
+ /// Synchronizes access to the message counter collection.
+ private readonly object MessageCounterSync = new object();
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initialize new instance of this type with defaults.
+ ///
+ public CounterPushPatternViewModel()
+ {
+ InitializeDefaults();
+ }
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Send raw message to all subscribers. In case that the phone-application
+ /// is not running, send tile update and increase tile counter.
+ ///
+ protected override void OnSend()
+ {
+ // Notify phone for having waiting messages.
+ var rawMsg = new RawPushNotificationMessage(MessageSendPriority.High)
+ {
+ RawData = Encoding.ASCII.GetBytes(RawMessage)
+ };
+
+ foreach (var subscriber in PushService.Subscribers)
+ {
+ rawMsg.SendAsync(
+ subscriber.ChannelUri,
+ result =>
+ {
+ Log(result);
+ OnRawSent(subscriber.UserName, result);
+ },
+ Log);
+ }
+ }
+
+ ///
+ /// On subscription change, reset the subscriber tile counter if exist.
+ ///
+ protected override void OnSubscribed(SubscriptionEventArgs e)
+ {
+ // Create a tile message to reset tile count.
+ var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ Count = 0,
+ BackgroundImageUri = BackgroundImageUri,
+ Title = Title
+ };
+
+ tileMsg.SendAsync(e.Subscription.ChannelUri, Log, Log);
+
+ ResetCounter(e.Subscription.UserName);
+ }
+
+ #endregion
+
+ #region Privates
+
+ private void OnRawSent(string userName, MessageSendResult result)
+ {
+ // In case that the device is disconnected, no need to send a tile message.
+ if (result.DeviceConnectionStatus == DeviceConnectionStatus.TempDisconnected)
+ {
+ return;
+ }
+
+ // Checking these three flags we can know what's the state of both the device and apllication.
+ bool isApplicationRunning =
+ result.SubscriptionStatus == SubscriptionStatus.Active &&
+ result.NotificationStatus == NotificationStatus.Received &&
+ result.DeviceConnectionStatus == DeviceConnectionStatus.Connected;
+
+ // In case that the application is not running, send a tile update with counter increase.
+ if (!isApplicationRunning)
+ {
+ var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ Count = IncreaseCounter(userName),
+ BackgroundImageUri = BackgroundImageUri,
+ Title = Title
+ };
+
+ tileMsg.SendAsync(result.ChannelUri, Log, Log);
+ }
+ }
+
+ private void ResetCounter(string userName)
+ {
+ lock (MessageCounterSync)
+ {
+ _messageCounter.Remove(userName);
+ }
+ }
+
+ private int IncreaseCounter(string userName)
+ {
+ lock (MessageCounterSync)
+ {
+ int counter;
+ if (_messageCounter.TryGetValue(userName, out counter))
+ {
+ ++counter;
+ }
+ else
+ {
+ counter = 1;
+ }
+
+ _messageCounter[userName] = counter;
+ return counter;
+ }
+ }
+
+ private void InitializeDefaults()
+ {
+ DisplayName = "Counter";
+ Description = "Send push notification message of Tile type, with a counter value. Each time a push notification message is sent, the counter value increases by one, unless user is running the application and notifies the server.";
+ BackgroundImageUri = TileImages.Length > 1 ? TileImages[1] : TileImages.FirstOrDefault();
+ RawMessage = "Game Update";
+ Count = 0;
+ Title = "Updates";
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CustomTileImagePushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CustomTileImagePushPatternViewModel.cs
new file mode 100644
index 0000000..300b746
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/CustomTileImagePushPatternViewModel.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Input;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+using System.Windows;
+using System.Windows.Controls.Primitives;
+using System.Windows.Media;
+using System.IO;
+using System.Reflection;
+using Microsoft.Win32;
+
+using WindowsPhone.Recipes.Push.Server.Behaviors;
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+using WindowsPhone.Recipes.Push.Server.Services;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents the Custom Tile Image push notification pattern.
+ ///
+ ///
+ /// Send a tile update with a dynamically created image located in the remote server (in our case localhost).
+ /// The image will be dynamically generated upon each request. The tile Count and Title in the
+ /// payload are optional.
+ ///
+ [Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class CustomTileImagePushPatternViewModel : PushPatternViewModel, IVisualHost
+ {
+ #region Constants
+
+ /// Tile image maximum width.
+ public const int TileImageWidth = 173;
+
+ /// Tile image maximum height.
+ public const int TileImageHeight = 173;
+
+ /// Tile image dpi.
+ public const int TileImageDpi = 96;
+
+ #endregion
+
+ #region Fields
+
+ /// Collection of brushes for choosing text message color.
+ private Brush[] _textColors;
+
+ /// Selected tile image background.
+ private ImageSource _tileBackground;
+
+ /// Text for diplaying on the tile custom image.
+ private string _freeText;
+
+ /// Tile custom image text size.
+ private double _textSize;
+
+ #endregion
+
+ #region Properties
+
+ [Import]
+ private ImageService ImageService { get; set; }
+
+ ///
+ /// Gets a list of brushes for choosing text message color.
+ ///
+ public Brush[] TextColors
+ {
+ get
+ {
+ if (_textColors == null)
+ {
+ _textColors = (from property in typeof(Brushes).GetProperties(BindingFlags.Static | BindingFlags.Public)
+ select (Brush)property.GetValue(null, null)).ToArray();
+ }
+
+ return _textColors;
+ }
+ }
+
+ ///
+ /// Gets or sets the visual element used for generating a custom image from.
+ ///
+ public Visual Visual
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Get or sets the prefered tile background image source.
+ ///
+ public ImageSource TileBackground
+ {
+ get { return _tileBackground; }
+
+ set
+ {
+ if (_tileBackground != value)
+ {
+ _tileBackground = value;
+ NotifyPropertyChanged("TileBackground");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a text to be displayed on the tile generated image.
+ ///
+ public string FreeText
+ {
+ get { return _freeText; }
+
+ set
+ {
+ if (_freeText != value)
+ {
+ _freeText = value;
+ NotifyPropertyChanged("FreeText");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the text size of the tile generated image.
+ ///
+ public double TextSize
+ {
+ get { return _textSize; }
+
+ set
+ {
+ if (_textSize != value)
+ {
+ _textSize = value;
+ NotifyPropertyChanged("TextSize");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Commands
+
+ ///
+ /// Gets the command for picking a tile background image.
+ ///
+ public ICommand PickImageCommand { get; private set; }
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initialize new instance of this type with defaults.
+ ///
+ public CustomTileImagePushPatternViewModel()
+ {
+ InitializeDefaults();
+
+ PickImageCommand = new RelayCommand(
+ p =>
+ {
+ // On execution, open file dialog for picking tile background image.
+ var openDialog = new OpenFileDialog
+ {
+ Title = "Tile Background",
+ Filter = "Jpeg|*.jpg|Bmp|*.bmp",
+ InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
+ Multiselect = false
+ };
+
+ if (openDialog.ShowDialog() == true)
+ {
+ TileBackground = new BitmapImage(new Uri(openDialog.FileName));
+ }
+ });
+ }
+
+ #endregion
+
+ #region Protected
+
+ protected override void OnActivated()
+ {
+ base.OnActivated();
+
+ // Register to the ImageService.ImageRequest event. This event is raised
+ // whenever ImageService.GetTileImage is called.
+ ImageService.ImageRequest += Service_ImageRequest;
+ }
+
+ protected override void OnDeactivated()
+ {
+ base.OnDeactivated();
+
+ ImageService.ImageRequest -= Service_ImageRequest;
+ }
+
+ protected override void OnSend()
+ {
+ // Starts by sending a tile notification to all relvant subscribers.
+ // This tile notification updates the tile with custom image.
+ var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ Count = Count,
+ Title = Title
+ };
+
+ foreach (var subscriber in PushService.Subscribers)
+ {
+ // Set the tile background image uri with the address of the ImageService.GetTileImage,
+ // REST service, using current subscriber channel uri as a parameter to bo sent to the service.
+ tileMsg.BackgroundImageUri = new Uri(string.Format(ImageService.GetTileImageService, string.Empty));
+ tileMsg.SendAsync(subscriber.ChannelUri, Log, Log);
+ }
+ }
+
+ #endregion
+
+ #region Privates
+
+ private void Service_ImageRequest(object sender, Services.ImageRequestEventArgs e)
+ {
+ // This event is raised by our local push-service as result of
+ // the tile msg we've sent to each subscriber. This is the time
+ // to pick the right tile image for the subscriber.
+ if (Visual != null)
+ {
+ RenderImage(Visual, e.ImageStream);
+ }
+ }
+
+ private static void RenderImage(Visual visual, Stream stream)
+ {
+ // The next lines of code uses WPF to dynamically create an image.
+ // In a real server we shouldn't use WPF, hence a 3rd party image generator library is required.
+ var renderer = new RenderTargetBitmap(TileImageWidth, TileImageHeight, TileImageDpi, TileImageDpi, PixelFormats.Pbgra32);
+ renderer.Render(visual);
+
+ var pngEncoder = new PngBitmapEncoder();
+ pngEncoder.Frames.Add(BitmapFrame.Create(renderer));
+ pngEncoder.Save(stream);
+ }
+
+ private void InitializeDefaults()
+ {
+ DisplayName = "Custom Tile";
+ Description = "Send a tile update with a dynamically created image located in the remote server (in our case localhost). The image will be dynamically generated upon each request. The tile Count and Title in the payload are optional.";
+ TextSize = 20;
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/OneTimePushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/OneTimePushPatternViewModel.cs
new file mode 100644
index 0000000..cb33927
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/OneTimePushPatternViewModel.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Input;
+using System.IO;
+using Microsoft.Win32;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents the One Time push notification pattern.
+ ///
+ ///
+ /// This is the simplest push notification pattern of just pushing single time message
+ /// to a registered client.
+ ///
+ [Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class OneTimePushPatternViewModel : PushPatternViewModel
+ {
+ #region Properties
+
+ ///
+ /// Gets or sets a value indicating if tile message should be sent.
+ ///
+ public bool IsTileEnabled { get; set; }
+
+ ///
+ /// Gets or sets a value indicating if toast message should be sent.
+ ///
+ public bool IsToastEnabled { get; set; }
+
+ ///
+ /// Gets or sets a value indicating if raw message should be sent.
+ ///
+ public bool IsRawEnabled { get; set; }
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initialize new instance of this type with defaults.
+ ///
+ public OneTimePushPatternViewModel()
+ {
+ InitializeDefaults();
+ }
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// Depends on what message was selected, send all subscribers zero or all three push message types (Tile, Toast, Raw).
+ ///
+ protected override void OnSend()
+ {
+ var messages = new List();
+
+ if (IsTileEnabled)
+ {
+ // Prepare a tile push notification message.
+ messages.Add(new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ BackgroundImageUri = BackgroundImageUri,
+ Count = Count,
+ Title = Title
+ });
+ }
+
+
+ if (IsToastEnabled)
+ {
+ // Prepare a toast push notification message.
+ messages.Add(new ToastPushNotificationMessage(MessageSendPriority.High)
+ {
+ Title = ToastTitle,
+ SubTitle = ToastSubTitle
+ });
+ }
+
+ if (IsRawEnabled)
+ {
+ // Prepare a raw push notification message.
+ messages.Add(new RawPushNotificationMessage(MessageSendPriority.High)
+ {
+ RawData = Encoding.ASCII.GetBytes(RawMessage)
+ });
+ }
+
+ foreach (var subscriber in PushService.Subscribers)
+ {
+ messages.ForEach(m => m.SendAsync(subscriber.ChannelUri, Log, Log));
+ }
+ }
+
+ #endregion
+
+ #region Privates
+
+ private void InitializeDefaults()
+ {
+ DisplayName = "One Time";
+ Description = "This is the simplest push notification pattern of just pushing single time message to a registered client.";
+ Count = 1;
+ Title = "Game Update";
+ ToastTitle = Title;
+ ToastSubTitle = "Game has been released";
+ RawMessage = ToastSubTitle;
+ IsTileEnabled = true;
+ IsToastEnabled = true;
+ IsRawEnabled = true;
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/PushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/PushPatternViewModel.cs
new file mode 100644
index 0000000..62b92ad
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/PushPatternViewModel.cs
@@ -0,0 +1,352 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Input;
+
+using WindowsPhone.Recipes.Push.Server.Services;
+using System.Windows;
+using WindowsPhone.Recipes.Push.Server.Models;
+using WindowsPhone.Recipes.Push.Messasges;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents a base class for all push pattern view models.
+ ///
+ ///
+ /// A push pattern view model contains the logic and behavior of a server side push notification pattern.
+ /// For demonstration purposes, and since we are using WPF as the 'face' of this server, each view model
+ /// exposes properties and commands to be controlled and activated by this server UI.
+ /// You can find more information about the MVVM pattern in .
+ ///
+ internal abstract class PushPatternViewModel : ViewModelBase
+ {
+ #region Fields
+
+ /// Indicates if current pattern is active or not.
+ private bool _isActive;
+
+ /// Collection of tile image relative uri's available in the phone application.
+ private Uri[] _tileImages;
+
+ /// Selected tile background image uri.
+ private Uri _backgroundImageUri;
+
+ /// Tile message count.
+ private int _count;
+
+ /// Tile message title.
+ private string _title;
+
+ /// Toast message title.
+ private string _toastTitle;
+
+ /// Toast message sub title.
+ private string _toastSubTitle;
+
+ /// Raw text message.
+ private string _rawMessage;
+
+ #endregion
+
+ #region Properties
+
+ [Import]
+ protected PushService PushService { get; private set; }
+
+ [Import]
+ private IMessageSendResultLogger ResultLogger { get; set; }
+
+ ///
+ /// Gets current pattern display name.
+ ///
+ public string DisplayName { get; protected set; }
+
+ ///
+ /// Gets current pattern description text.
+ ///
+ public string Description { get; protected set; }
+
+ ///
+ /// Gets or sets value for indicating whether this pattern is active or not.
+ ///
+ public bool IsActive
+ {
+ get
+ {
+ return _isActive;
+ }
+
+ set
+ {
+ if (_isActive != value)
+ {
+ _isActive = value;
+ if (_isActive)
+ {
+ OnActivated();
+ }
+ else
+ {
+ OnDeactivated();
+ }
+
+ NotifyPropertyChanged("IsActive");
+ }
+ }
+ }
+
+ ///
+ /// Gets a collection of tile image uris available in the phone client application.
+ ///
+ public Uri[] TileImages
+ {
+ get
+ {
+ if (_tileImages == null)
+ {
+ _tileImages = new Uri[]
+ {
+ ToUri("TileBackground1.jpg"),
+ ToUri("TileBackground2.jpg"),
+ ToUri("TileBackground3.jpg"),
+ };
+
+ BackgroundImageUri = _tileImages[0];
+ }
+
+ return _tileImages;
+ }
+ }
+
+ ///
+ /// Gets or sets the tile background uri.
+ ///
+ public Uri BackgroundImageUri
+ {
+ get { return _backgroundImageUri; }
+
+ set
+ {
+ if (_backgroundImageUri != value)
+ {
+ _backgroundImageUri = value;
+ NotifyPropertyChanged("BackgroundImageUri");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the tile count.
+ ///
+ public int Count
+ {
+ get { return _count; }
+
+ set
+ {
+ if (_count != value)
+ {
+ _count = value;
+ NotifyPropertyChanged("Count");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the tile tiltle.
+ ///
+ public string Title
+ {
+ get { return _title; }
+
+ set
+ {
+ if (_title != value)
+ {
+ _title = value;
+ NotifyPropertyChanged("Title");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the toast title.
+ ///
+ public string ToastTitle
+ {
+ get { return _toastTitle; }
+
+ set
+ {
+ if (_toastTitle != value)
+ {
+ _toastTitle = value;
+ NotifyPropertyChanged("ToastTitle");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the toast sub-title.
+ ///
+ public string ToastSubTitle
+ {
+ get { return _toastSubTitle; }
+
+ set
+ {
+ if (_toastSubTitle != value)
+ {
+ _toastSubTitle = value;
+ NotifyPropertyChanged("ToastSubTitle");
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the raw text message.
+ ///
+ public string RawMessage
+ {
+ get { return _rawMessage; }
+
+ set
+ {
+ if (_rawMessage != value)
+ {
+ _rawMessage = value;
+ NotifyPropertyChanged("RawMessage");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Commands
+
+ ///
+ /// Gets the command which executes the send operation.
+ ///
+ public ICommand SendCommand
+ {
+ get
+ {
+ return new RelayCommand(p =>
+ {
+ try
+ {
+ OnSend();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Send Error");
+ }
+ });
+ }
+ }
+
+ #endregion
+
+ #region Protected
+
+ ///
+ /// Override this to send push message according to the pattern behavior.
+ ///
+ protected abstract void OnSend();
+
+ ///
+ /// Override this to add additional pattern-activation logic.
+ ///
+ protected virtual void OnActivated()
+ {
+ UpdateClient();
+
+ PushService.Subscribed += PushService_Subscribed;
+ PushService.GetInfo += PushService_GetInfo;
+ }
+
+ ///
+ /// Override this to add additional pattern-deactivation logic.
+ ///
+ protected virtual void OnDeactivated()
+ {
+ PushService.Subscribed -= PushService_Subscribed;
+ PushService.GetInfo -= PushService_GetInfo;
+ }
+
+ ///
+ /// Override this to add logic when clients login.
+ ///
+ protected virtual void OnSubscribed(SubscriptionEventArgs args)
+ {
+ }
+
+ ///
+ /// Override this to add logic when clients request server's info.
+ ///
+ protected virtual void OnGetInfo(ServerInfoEventArgs args)
+ {
+ args.ServerInfo = new ServerInfo
+ {
+ PushPattern = DisplayName,
+ Counter = Count
+ };
+ }
+
+ ///
+ /// Logs push message result.
+ ///
+ protected void Log(MessageSendResult result)
+ {
+ ResultLogger.Log(DisplayName, result);
+ }
+
+ ///
+ /// Logs push message error.
+ ///
+ protected void Log(MessageSendException exception)
+ {
+ ResultLogger.Log(DisplayName, exception);
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ private void UpdateClient()
+ {
+ // Notify subscribers to get new info from the server.
+ foreach (var subscriber in PushService.Subscribers)
+ {
+ new RawPushNotificationMessage(MessageSendPriority.High)
+ {
+ RawData = Encoding.ASCII.GetBytes("Update Info")
+ }.SendAsync(subscriber.ChannelUri);
+ }
+ }
+
+ private void PushService_Subscribed(object sender, SubscriptionEventArgs args)
+ {
+ OnSubscribed(args);
+ }
+
+ private void PushService_GetInfo(object sender, ServerInfoEventArgs args)
+ {
+ OnGetInfo(args);
+ }
+
+ #endregion
+
+ #region Helpers
+
+ private static Uri ToUri(string imageName)
+ {
+ return new Uri(string.Format("/Resources/TileImages/{0}", imageName), UriKind.Relative);
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/TileSchedulePushPatternViewModel.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/TileSchedulePushPatternViewModel.cs
new file mode 100644
index 0000000..f889c90
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/Patterns/TileSchedulePushPatternViewModel.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Input;
+using System.IO;
+using Microsoft.Win32;
+
+using WindowsPhone.Recipes.Push.Messasges;
+using WindowsPhone.Recipes.Push.Server.Models;
+using WindowsPhone.Recipes.Push.Server.Services;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// Represents the Tile Schedule push notification pattern.
+ ///
+ ///
+ /// This push pattern is passive. The user schedule a tile image update request,
+ /// by using the Windows Phone API, and at the time, MPNS fetches the image using
+ /// the uri provided with the request.
+ ///
+ [Export(typeof(PushPatternViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class TileSchedulePushPatternViewModel : PushPatternViewModel
+ {
+ #region Fields
+
+ private string _imageFileName;
+
+ #endregion
+
+ #region Properties
+
+ [Import]
+ private ImageService ImageService { get; set; }
+
+ ///
+ /// Gets or sets a image file name sent by the user.
+ ///
+ public string ImageFileName
+ {
+ get { return _imageFileName; }
+
+ set
+ {
+ if (_imageFileName != value)
+ {
+ _imageFileName = value;
+ NotifyPropertyChanged("ImageFileName");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Ctor
+
+ ///
+ /// Initialize new instance of this type with defaults.
+ ///
+ public TileSchedulePushPatternViewModel()
+ {
+ InitializeDefaults();
+ }
+
+ #endregion
+
+ #region Overrides
+
+ protected override void OnActivated()
+ {
+ base.OnActivated();
+
+ // Register to the PushService.TileUpdateRequest event. This event is raised
+ // whenever a user asks to update its tile.
+ PushService.TileUpdateRequest += PushService_TileUpdateRequest;
+
+ // Register to the ImageService.ImageRequest event. This event is raised
+ // whenever ImageService.GetTileImage is called.
+ ImageService.ImageRequest += Service_ImageRequest;
+ }
+
+ protected override void OnDeactivated()
+ {
+ base.OnDeactivated();
+
+ PushService.TileUpdateRequest -= PushService_TileUpdateRequest;
+ ImageService.ImageRequest -= Service_ImageRequest;
+ }
+
+ protected override void OnSend()
+ {
+ // Nothing to do here.
+ }
+
+ #endregion
+
+ #region Privates
+
+ private void PushService_TileUpdateRequest(object sender, TileUpdateRequestEventArgs e)
+ {
+ // Send a tile notification message to the relevant device.
+ var tileMsg = new TilePushNotificationMessage(MessageSendPriority.High)
+ {
+ BackgroundImageUri = new Uri(string.Format(ImageService.GetTileImageService, e.Parameter))
+ };
+
+ tileMsg.SendAsync(e.ChannelUri, Log, Log);
+ }
+
+ private void Service_ImageRequest(object sender, Services.ImageRequestEventArgs e)
+ {
+ ImageFileName = e.Parameter;
+
+ // This event is raised by our local push-service as result of
+ // the tile msg we've sent to a subscriber. This is the time
+ // to pick the right tile image for the subscriber.
+ string imageFile = Path.Combine("Resources/TileImages/Numbers", e.Parameter);
+ if (File.Exists(imageFile))
+ {
+ using (var reader = File.OpenRead(imageFile))
+ {
+ byte[] imageBuffer = new byte[reader.Length];
+ int bytesRead = reader.Read(imageBuffer, 0, imageBuffer.Length);
+ e.ImageStream.Write(imageBuffer, 0, bytesRead);
+ }
+ }
+ }
+
+ private void InitializeDefaults()
+ {
+ DisplayName = "Tile Schedule";
+ Description = "This push pattern is passive. The user schedule a tile image update request, by using the Windows Phone API, and at the time, MPNS fetches the image using the uri provided with the request.";
+ }
+
+ #endregion
+ }
+}
diff --git a/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/RelayCommand.cs b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/RelayCommand.cs
new file mode 100644
index 0000000..8b0ace5
--- /dev/null
+++ b/main/Libs/PushRecipe_WP7_SL/Source/WindowsPhone.Recipes.Push.Server/ViewModels/RelayCommand.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Diagnostics;
+using System.Windows.Input;
+
+namespace WindowsPhone.Recipes.Push.Server.ViewModels
+{
+ ///
+ /// A custom implementation of a WPF command, command whose sole purpose is
+ /// to relay its functionality to other objects by invoking delegates.
+ /// The default return value for the CanExecute method is 'true'.
+ ///
+ public class RelayCommand : ICommand
+ {
+ #region Fields
+
+ private readonly Action