From 4d92383d1961c421117a3c378b2500c9ce7bb9d4 Mon Sep 17 00:00:00 2001 From: Mohamed CHOUCHANE Date: Thu, 7 Dec 2017 00:34:59 +0100 Subject: [PATCH] [WPF] Maps project for WPF backend (#1335) * Add Xamarin.Forms.Maps.WPF * Remove french comment in AssemblyInfo.cs * Remove private keyword --- Xamarin.Forms.Maps.WPF/FormsMaps.cs | 30 ++ Xamarin.Forms.Maps.WPF/FormsPushPin.cs | 53 ++++ Xamarin.Forms.Maps.WPF/GeocoderBackend.cs | 28 ++ Xamarin.Forms.Maps.WPF/MapRenderer.cs | 298 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 25 ++ .../Properties/Resources.Designer.cs | 63 ++++ .../Properties/Resources.resx | 117 +++++++ .../Properties/Settings.Designer.cs | 26 ++ .../Properties/Settings.settings | 7 + .../Xamarin.Forms.Maps.WPF.csproj | 97 ++++++ Xamarin.Forms.Maps.WPF/packages.config | 4 + Xamarin.Forms.sln | 55 ++++ 12 files changed, 803 insertions(+) create mode 100644 Xamarin.Forms.Maps.WPF/FormsMaps.cs create mode 100644 Xamarin.Forms.Maps.WPF/FormsPushPin.cs create mode 100644 Xamarin.Forms.Maps.WPF/GeocoderBackend.cs create mode 100644 Xamarin.Forms.Maps.WPF/MapRenderer.cs create mode 100644 Xamarin.Forms.Maps.WPF/Properties/AssemblyInfo.cs create mode 100644 Xamarin.Forms.Maps.WPF/Properties/Resources.Designer.cs create mode 100644 Xamarin.Forms.Maps.WPF/Properties/Resources.resx create mode 100644 Xamarin.Forms.Maps.WPF/Properties/Settings.Designer.cs create mode 100644 Xamarin.Forms.Maps.WPF/Properties/Settings.settings create mode 100644 Xamarin.Forms.Maps.WPF/Xamarin.Forms.Maps.WPF.csproj create mode 100644 Xamarin.Forms.Maps.WPF/packages.config diff --git a/Xamarin.Forms.Maps.WPF/FormsMaps.cs b/Xamarin.Forms.Maps.WPF/FormsMaps.cs new file mode 100644 index 000000000..2747403fa --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/FormsMaps.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.Forms.Maps.WPF; + +namespace Xamarin +{ + public static class FormsMaps + { + static bool s_isInitialized; + + internal static string AuthenticationToken { get; set; } + + public static void Init(string authenticationToken) + { + AuthenticationToken = authenticationToken; + Init(); + } + + public static void Init() + { + if (s_isInitialized) + return; + GeocoderBackend.Register(); + s_isInitialized = true; + } + } +} diff --git a/Xamarin.Forms.Maps.WPF/FormsPushPin.cs b/Xamarin.Forms.Maps.WPF/FormsPushPin.cs new file mode 100644 index 000000000..3033591d8 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/FormsPushPin.cs @@ -0,0 +1,53 @@ +using Microsoft.Maps.MapControl.WPF; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Xamarin.Forms.Maps.WPF +{ + internal class FormsPushPin : Pushpin + { + public Pin Pin { get; private set; } + + internal FormsPushPin(Pin pin) + { + Pin = pin; + + UpdateLocation(); + + Loaded += FormsPushPin_Loaded; + Unloaded += FormsPushPin_Unloaded; + MouseDown += FormsPushPin_MouseDown; + } + + void FormsPushPin_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + Pin.PropertyChanged += PinPropertyChanged; + } + + void FormsPushPin_Unloaded(object sender, System.Windows.RoutedEventArgs e) + { + Pin.PropertyChanged -= PinPropertyChanged; + } + + void FormsPushPin_MouseDown(object sender, MouseButtonEventArgs e) + { + Pin.SendTap(); + } + + void PinPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == Pin.PositionProperty.PropertyName) + UpdateLocation(); + } + + void UpdateLocation() + { + Location = new Location(Pin.Position.Latitude, Pin.Position.Longitude); + } + } +} diff --git a/Xamarin.Forms.Maps.WPF/GeocoderBackend.cs b/Xamarin.Forms.Maps.WPF/GeocoderBackend.cs new file mode 100644 index 000000000..ae896fb34 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/GeocoderBackend.cs @@ -0,0 +1,28 @@ +using Microsoft.Maps.MapControl.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Xamarin.Forms.Maps.WPF +{ + internal class GeocoderBackend + { + public static void Register() + { + Geocoder.GetPositionsForAddressAsyncFunc = GetPositionsForAddress; + Geocoder.GetAddressesForPositionFuncAsync = GetAddressesForPositionAsync; + } + + static async Task> GetAddressesForPositionAsync(Position position) + { + return new List(); + } + + static async Task> GetPositionsForAddress(string address) + { + return new List(); + } + } +} diff --git a/Xamarin.Forms.Maps.WPF/MapRenderer.cs b/Xamarin.Forms.Maps.WPF/MapRenderer.cs new file mode 100644 index 000000000..552ba6f9a --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/MapRenderer.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.Forms.Platform.WPF; +using Microsoft.Maps.MapControl.WPF; +using WMap = Microsoft.Maps.MapControl.WPF.Map; +using System.ComponentModel; +using System.Collections.Specialized; +using System.Device.Location; +using System.Windows.Threading; + +namespace Xamarin.Forms.Maps.WPF +{ + public class MapRenderer : ViewRenderer + { + DispatcherTimer _timer; + + protected override async void OnElementChanged(ElementChangedEventArgs e) + { + if (e.OldElement != null) // Clear old element event + { + MessagingCenter.Unsubscribe(this, "MapMoveToRegion"); + ((ObservableCollection)e.OldElement.Pins).CollectionChanged -= OnCollectionChanged; + } + + if (e.NewElement != null) + { + if (Control == null) // construct and SetNativeControl and suscribe control event + { + SetNativeControl(new WMap()); + Control.CredentialsProvider = new ApplicationIdCredentialsProvider(FormsMaps.AuthenticationToken); + Control.ViewChangeOnFrame += Control_ViewChangeOnFrame; + } + + // Update control property + UpdateMapType(); + await UpdateIsShowingUser(); + UpdateHasZoomEnabled(); + UpdateHasZoomEnabled(); + UpdateVisibleRegion(); + + // Suscribe element event + MessagingCenter.Subscribe(this, "MapMoveToRegion", (s, a) => MoveToRegion(a), Element); + ((ObservableCollection)Element.Pins).CollectionChanged += OnCollectionChanged; + } + + base.OnElementChanged(e); + } + + void Control_ViewChangeOnFrame(object sender, MapEventArgs e) + { + UpdateVisibleRegion(); + } + + protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Map.MapTypeProperty.PropertyName) + UpdateMapType(); + else if (e.PropertyName == Map.IsShowingUserProperty.PropertyName) + await UpdateIsShowingUser(); + else if (e.PropertyName == Map.HasScrollEnabledProperty.PropertyName) + UpdateHasScrollEnabled(); + else if (e.PropertyName == Map.HasZoomEnabledProperty.PropertyName) + UpdateHasZoomEnabled(); + } + + void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (Pin pin in e.NewItems) + LoadPin(pin); + break; + case NotifyCollectionChangedAction.Move: + // no matter + break; + case NotifyCollectionChangedAction.Remove: + foreach (Pin pin in e.OldItems) + RemovePin(pin); + break; + case NotifyCollectionChangedAction.Replace: + foreach (Pin pin in e.OldItems) + RemovePin(pin); + foreach (Pin pin in e.NewItems) + LoadPin(pin); + break; + case NotifyCollectionChangedAction.Reset: + ClearPins(); + break; + } + } + + void UpdateVisibleRegion() + { + if (Control == null || Element == null) + return; + + try + { + var boundingBox = Control.BoundingRectangle; + + if (boundingBox != null) + { + var center = new Position(boundingBox.Center.Latitude, boundingBox.Center.Longitude); + var latitudeDelta = Math.Abs(boundingBox.Northwest.Latitude - boundingBox.Southeast.Latitude); + var longitudeDelta = Math.Abs(boundingBox.Northwest.Longitude - boundingBox.Southeast.Longitude); + Element.SetVisibleRegion(new MapSpan(center, latitudeDelta, longitudeDelta)); + } + } + catch (Exception) + { + } + } + + async Task UpdateIsShowingUser(bool moveToLocation = true) + { + if (Control == null || Element == null) return; + + if (Element.IsShowingUser) + { + var location = await GetCurrentLocation(); + if(location != null) + LoadUserPosition(location, moveToLocation); + + if (Control == null || Element == null) return; + + if (_timer == null) + { + _timer = new DispatcherTimer(); + _timer.Tick += async (s, o) => await UpdateIsShowingUser(moveToLocation: false); + _timer.Interval = TimeSpan.FromSeconds(15); + } + + if (!_timer.IsEnabled) + _timer.Start(); + } + else + { + _timer?.Stop(); + + if (Control.Children.Contains(_userPositionPin)) + Control.Children.Remove(_userPositionPin); + } + } + + void LoadPins() + { + foreach (var pin in Element.Pins) + LoadPin(pin); + } + + void ClearPins() + { + Control.Children.Clear(); + } + + void RemovePin(Pin pinToRemove) + { + var pushPin = Control.Children.Cast().FirstOrDefault(x => x.Pin == pinToRemove); + + if (pushPin != null) + Control.Children.Remove(pushPin); + } + + void LoadPin(Pin pin) + { + Control.Children.Add(new FormsPushPin(pin)); + } + + void UpdateMapType() + { + switch (Element.MapType) + { + case MapType.Street: + Control.Mode = new RoadMode(); + break; + case MapType.Satellite: + Control.Mode = new AerialMode(); + break; + case MapType.Hybrid: + Control.Mode = new AerialMode(true); + break; + } + } + + void MoveToRegion(MapSpan span) + { + var nw = new Location + { + Latitude = span.Center.Latitude + span.LatitudeDegrees / 2, + Longitude = span.Center.Longitude - span.LongitudeDegrees / 2 + }; + var se = new Location + { + Latitude = span.Center.Latitude - span.LatitudeDegrees / 2, + Longitude = span.Center.Longitude + span.LongitudeDegrees / 2 + }; + + Control.SetView(new LocationRect(nw, se)); + } + + FormsPushPin _userPositionPin; + + void LoadUserPosition(GeoCoordinate userCoordinate, bool center) + { + if (Control == null || Element == null) return; + + var userPosition = new Location + { + Latitude = userCoordinate.Latitude, + Longitude = userCoordinate.Longitude + }; + + if (Control.Children.Contains(_userPositionPin)) + Control.Children.Remove(_userPositionPin); + + _userPositionPin = new FormsPushPin(new Pin() { Position = new Position(userCoordinate.Latitude, userCoordinate.Longitude) }); + + Control.Children.Add(_userPositionPin); + + if (center) + { + Control.Center = userPosition; + Control.ZoomLevel = 13; + } + } + + void UpdateHasZoomEnabled() + { + } + + void UpdateHasScrollEnabled() + { + } + + bool _isDisposed; + + protected override void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + _timer?.Stop(); + _timer = null; + + if (Control != null) + { + Control.ViewChangeOnFrame -= Control_ViewChangeOnFrame; + } + + if (Element != null) + { + MessagingCenter.Unsubscribe(this, "MapMoveToRegion"); + ((ObservableCollection)Element.Pins).CollectionChanged -= OnCollectionChanged; + } + } + + _isDisposed = true; + base.Dispose(disposing); + } + + + /* Tools */ + Task GetCurrentLocation() + { + TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); + + GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(); + watcher.StatusChanged += (sender, e) => + { + switch (e.Status) + { + case GeoPositionStatus.Disabled: + watcher.Stop(); + taskCompletionSource.SetResult(null); + break; + } + }; + + watcher.PositionChanged += (sender, e) => + { + watcher.Stop(); + taskCompletionSource.SetResult(e.Position.Location); + }; + watcher.Start(); + + return taskCompletionSource.Task; + } + } +} diff --git a/Xamarin.Forms.Maps.WPF/Properties/AssemblyInfo.cs b/Xamarin.Forms.Maps.WPF/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c10e6acaf --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; +using Xamarin.Forms.Maps; +using Xamarin.Forms.Maps.WPF; +using Xamarin.Forms.Platform.WPF; + +[assembly: AssemblyTitle("Xamarin.Forms.Maps.WPF")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Xamarin.Forms.Maps.WPF")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: ExportRenderer(typeof(Map), typeof(MapRenderer))] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Xamarin.Forms.Maps.WPF/Properties/Resources.Designer.cs b/Xamarin.Forms.Maps.WPF/Properties/Resources.Designer.cs new file mode 100644 index 000000000..f9dbe0434 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.42000 +// +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace Xamarin.Forms.Maps.WPF.Properties { + using System; + + + /// + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. + /// + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.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() { + } + + /// + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. + /// + [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("Xamarin.Forms.Maps.WPF.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. + /// + [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/Xamarin.Forms.Maps.WPF/Properties/Resources.resx b/Xamarin.Forms.Maps.WPF/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/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/Xamarin.Forms.Maps.WPF/Properties/Settings.Designer.cs b/Xamarin.Forms.Maps.WPF/Properties/Settings.Designer.cs new file mode 100644 index 000000000..c86a64cb2 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.42000 +// +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace Xamarin.Forms.Maps.WPF.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.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/Xamarin.Forms.Maps.WPF/Properties/Settings.settings b/Xamarin.Forms.Maps.WPF/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Maps.WPF/Xamarin.Forms.Maps.WPF.csproj b/Xamarin.Forms.Maps.WPF/Xamarin.Forms.Maps.WPF.csproj new file mode 100644 index 000000000..10f35574f --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/Xamarin.Forms.Maps.WPF.csproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4} + library + Xamarin.Forms.Maps.WPF + Xamarin.Forms.Maps.WPF + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.Maps.MapControl.WPF.1.0.0.3\lib\net40-Client\Microsoft.Maps.MapControl.WPF.dll + + + + + + + + + + + + 4.0 + + + + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {57b8b73d-c3b5-4c42-869e-7b2f17d354ac} + Xamarin.Forms.Core + + + {7d13bac2-c6a4-416a-b07e-c169b199e52b} + Xamarin.Forms.Maps + + + {140bc260-8b15-4d3a-b1b0-ddd8072918cc} + Xamarin.Forms.Platform.WPF + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Maps.WPF/packages.config b/Xamarin.Forms.Maps.WPF/packages.config new file mode 100644 index 000000000..3834297b2 --- /dev/null +++ b/Xamarin.Forms.Maps.WPF/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Xamarin.Forms.sln b/Xamarin.Forms.sln index 75730e36f..947410987 100644 --- a/Xamarin.Forms.sln +++ b/Xamarin.Forms.sln @@ -141,6 +141,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.ControlGaller EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Platform.WPF", "Xamarin.Forms.Platform.WPF\Xamarin.Forms.Platform.WPF.csproj", "{140BC260-8B15-4D3A-B1B0-DDD8072918CC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Maps.WPF", "Xamarin.Forms.Maps.WPF\Xamarin.Forms.Maps.WPF.csproj", "{89B0DB73-A32E-447C-9390-A2A59D89B2E4}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution Xamarin.Forms.Controls.Issues\Xamarin.Forms.Controls.Issues.Shared\Xamarin.Forms.Controls.Issues.Shared.projitems*{0a39a74b-6f7a-4d41-84f2-b0ccdce899df}*SharedItemsImports = 4 @@ -2572,6 +2574,58 @@ Global {140BC260-8B15-4D3A-B1B0-DDD8072918CC}.Release|x64.Build.0 = Release|Any CPU {140BC260-8B15-4D3A-B1B0-DDD8072918CC}.Release|x86.ActiveCfg = Release|Any CPU {140BC260-8B15-4D3A-B1B0-DDD8072918CC}.Release|x86.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|ARM.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|Templates.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|Templates.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|x64.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|Any CPU.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|ARM.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|ARM.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|iPhone.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|Templates.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|Templates.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|x64.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|x64.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|x86.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.AppStore|x86.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|ARM.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|ARM.Build.0 = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|Templates.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|Templates.Build.0 = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|x64.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|x64.Build.0 = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|x86.ActiveCfg = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Debug|x86.Build.0 = Debug|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|Any CPU.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|ARM.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|ARM.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|iPhone.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|Templates.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|Templates.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|x64.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|x64.Build.0 = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|x86.ActiveCfg = Release|Any CPU + {89B0DB73-A32E-447C-9390-A2A59D89B2E4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2629,6 +2683,7 @@ Global {83790029-272E-45AF-A41D-E7716684E5B8} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} {03A51E5B-0A1E-41F0-AAE3-4B19406F7340} = {4F5E2D21-17F6-4A42-B8FB-D03D82E24EC8} {140BC260-8B15-4D3A-B1B0-DDD8072918CC} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} + {89B0DB73-A32E-447C-9390-A2A59D89B2E4} = {132FB9A4-613F-44CE-95D5-758D32D231DD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {650AE971-2F29-46A8-822C-FB4FCDC6A9A0}